home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 1 / ETO Development Tools 1.iso / Tools - Objects / MacApp / MacApp 2.0 CD Release / MacApp 2.0 (Many Libraries) / Libraries / UMacAppUtilities.inc1.p < prev    next >
Encoding:
Text File  |  1990-03-27  |  71.3 KB  |  2,823 lines  |  [TEXT/MPS ]

  1. {$P}
  2. {[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]}
  3. {UMacAppUtilities.inc1.p}
  4. {Copyright © 1984-1990 Apple Computer, Inc.  All rights reserved.}
  5.  
  6. { These are utilities.    Treat them like language extensions. }
  7. {$W+}
  8. {$R-}
  9. {$Init-}
  10. {$OV-}
  11. {$IFC qNames}
  12. {$D+}
  13. {$ENDC}
  14.  
  15. {--------------------------------------------------------------------------------------------------}
  16.                                                         { The debugger uses some of this unit's
  17.                                                          types in it's interface so we must use
  18.                                                          externals. !!! Resolve this. }
  19.  
  20. TYPE
  21.     DebugForceOptions    = (forceOn, forceOff, forceUnchanged);
  22.  
  23. VAR
  24.     {$Push} {$J+}
  25.     gWorkPort:            GrafPtr;                        { Found in UMacApp.p }
  26.     {$Pop}
  27.  
  28. FUNCTION DebugCanReadLn: Boolean;
  29.     EXTERNAL;
  30.  
  31. FUNCTION DebugCanWriteLn: Boolean;
  32.     EXTERNAL;
  33.  
  34. PROCEDURE DebugEndForce;
  35.     EXTERNAL;
  36.  
  37. PROCEDURE ProgramBreak(grievance: Str255);
  38.     EXTERNAL;
  39.  
  40. PROCEDURE DebugForceOutput(ToWindow, ToFile: DebugForceOptions);
  41.     EXTERNAL;
  42.  
  43. {--------------------------------------------------------------------------------------------------}
  44. {$S MAUtilitiesRes}
  45.  
  46. PROCEDURE BlockSet(destPtr: Ptr;
  47.                    byteCount: longint;
  48.                    setVal: UNIV SignedByte);
  49.  
  50. { ??? should be improved to do longword setting. }
  51.  
  52.     VAR
  53.         endPtr:             Ptr;
  54.  
  55.     BEGIN
  56.     destPtr := Ptr(StripLong(destPtr));
  57.     endPtr := Ptr(Ord(destPtr) + byteCount);
  58.     WHILE Ord(destPtr) < Ord(endPtr) DO
  59.         BEGIN
  60.         destPtr^ := setVal;
  61.         destPtr := Ptr(Ord(destPtr) + 1);
  62.         END;
  63.     END;
  64.  
  65. {--------------------------------------------------------------------------------------------------}
  66. {$S MAUtilitiesRes}
  67.  
  68. FUNCTION CanWriteLn: Boolean;
  69.  
  70.     BEGIN
  71.     {$IFC qDebug}
  72.     CanWriteLn := DebugCanWriteLn;
  73.     {$ELSEC}
  74.     CanWriteLn := FALSE;
  75.     {$ENDC}
  76.     END;
  77.  
  78. {--------------------------------------------------------------------------------------------------}
  79. {$S MAUtilitiesRes}
  80.  
  81. FUNCTION CanReadLn: Boolean;
  82.  
  83.     BEGIN
  84.     {$IFC qDebug}
  85.     CanReadLn := DebugCanReadLn;
  86.     {$ELSEC}
  87.     CanReadLn := FALSE;
  88.     {$ENDC}
  89.     END;
  90.  
  91. {--------------------------------------------------------------------------------------------------}
  92. {$Push}
  93. {$MC68020-}                                             { Need to be able to alert user if this
  94.                                                          isn't a 68020 machine }
  95. {$S MAUtilitiesRes}                                     { This must always be in a resident segment
  96.                                                          as aRect may be within a handle }
  97.  
  98. PROCEDURE CenterRectOnScreen(VAR aRect: Rect;
  99.                              horizontally, vertically, forDialog: Boolean);
  100.  
  101.     VAR
  102.         screenSize:         Point;
  103.         rectSize:            Point;
  104.         newSize:            INTEGER;
  105.  
  106.     BEGIN
  107.     { Calculate screen size minus menu bar }
  108.     WITH screenBits.bounds DO
  109.         SetPt(screenSize, right - left, bottom - top - gMBarHeight);
  110.                                                         { ??? should we use the same algorithm
  111.                                                          as in TWindow.GetMaxIntersectedDevice }
  112.     WITH aRect DO
  113.         BEGIN
  114.         SetPt(rectSize, right - left, bottom - top);
  115.         IF horizontally THEN
  116.             left := (screenSize.h - rectSize.h) DIV 2;
  117.         IF vertically THEN
  118.             IF forDialog THEN
  119.                 BEGIN
  120.                 newSize := (screenSize.v - rectSize.v) DIV 5;
  121.                 top := Max(newSize, 10) + gMBarHeight;
  122.                 END
  123.             ELSE
  124.                 top := (screenSize.v - rectSize.v) DIV 2;
  125.  
  126.         right := left + rectSize.h;
  127.         bottom := top + rectSize.v;
  128.         END;
  129.     END;
  130. {$Pop}
  131.  
  132. {--------------------------------------------------------------------------------------------------}
  133. {$S MAFile}
  134.  
  135. FUNCTION CloseFile(dataRefnum, rsrcRefnum: INTEGER): OSErr;
  136.  
  137.     VAR
  138.         err:                OSErr;
  139.  
  140.     BEGIN
  141.     err := noErr;
  142.  
  143.     IF dataRefnum <> kNoFileRefnum THEN
  144.         err := FSClose(dataRefnum);
  145.  
  146.     IF rsrcRefnum <> kNoFileRefnum THEN
  147.         BEGIN
  148.         CloseResFile(rsrcRefnum);
  149.         IF err = noErr THEN
  150.             err := ResError;
  151.         END;
  152.  
  153.     CloseFile := err;
  154.     END;
  155.  
  156. {--------------------------------------------------------------------------------------------------}
  157. {$S MAUtilitiesRes}
  158.  
  159. FUNCTION CompareStrings(first, second: Str255): INTEGER;
  160.  
  161. {$IFC NOT qNeedsROM128k}
  162.     EXTERNAL;
  163. {$ELSEC}
  164.  
  165. BEGIN
  166. CompareStrings := RelString(first, second, TRUE, TRUE);
  167. END;
  168. {$ENDC}
  169.  
  170. {--------------------------------------------------------------------------------------------------}
  171. {$Push}
  172. {$MC68020-}
  173. {$S MAUtilitiesRes}
  174.  
  175. FUNCTION ConcatNumber(aString: Str255;
  176.                       aNumber: longint): Str255;
  177.  
  178.     VAR
  179.         numberString:        Str255;
  180.  
  181.     BEGIN
  182.     NumToString(aNumber, numberString);
  183.     ConcatNumber := CONCAT(aString, numberString);
  184.     END;
  185. {$Pop}
  186.  
  187. {--------------------------------------------------------------------------------------------------}
  188. {$S MAFields}
  189.  
  190. PROCEDURE ConfigRecFields(aTitle: Str255;
  191.                           VAR aConfigRec: ConfigRecord;
  192.                           PROCEDURE DoToField(fieldName: Str255;
  193.                                               fieldAddr: Ptr;
  194.                                               fieldType: INTEGER));
  195.  
  196.     CONST
  197.         envSE30             = 7;                        { Not in the MPW 3.0 interfaces }
  198.  
  199.     VAR
  200.         aString:            Str255;
  201.  
  202.     BEGIN
  203.     DoToField(aTitle, NIL, bTitle);
  204.     DoToField('  environsVersion', @aConfigRec.environsVersion, bInteger);
  205.  
  206.     CASE aConfigRec.machineType OF
  207.         envMac:
  208.             aString := 'envMac';
  209.         envXL:
  210.             aString := 'envXL';
  211.         envMachUnknown:
  212.             aString := 'envMachUnknown';
  213.         env512KE:
  214.             aString := 'env512KE';
  215.         envMacPlus:
  216.             aString := 'envMacPlus';
  217.         envSE:
  218.             aString := 'envSE';
  219.         envMacII:
  220.             aString := 'envMacII';
  221.         envMacIIx:
  222.             aString := 'envMacIIx';
  223.         envSE30:
  224.             aString := 'envSE30';
  225.         OTHERWISE
  226.             aString := 'envMachUnknown';
  227.     END;
  228.     DoToField('  machineType', @aString, bString);
  229.  
  230.     DoToField('  systemVersion', @aConfigRec.systemVersion, bHexInteger);
  231.  
  232.     CASE aConfigRec.processor OF
  233.         envCPUUnknown:
  234.             aString := 'envCPUUnknown';
  235.         env68000:
  236.             aString := 'env68000';
  237.         env68010:
  238.             aString := 'env68010';
  239.         env68020:
  240.             aString := 'env68020';
  241.         env68030:
  242.             aString := 'env68030';
  243.         OTHERWISE
  244.             aString := 'envCPUUnknown';
  245.     END;
  246.     DoToField('  processor', @aString, bString);
  247.  
  248.     DoToField('  hasFPU', @aConfigRec.hasFPU, bBoolean);
  249.     DoToField('  hasColorQD', @aConfigRec.hasColorQD, bBoolean);
  250.  
  251.     CASE aConfigRec.keyboardType OF
  252.         envUnknownKbd:
  253.             aString := 'envUnknownKbd';
  254.         envMacKbd:
  255.             aString := 'envMacKbd';
  256.         envMacAndPad:
  257.             aString := 'envMacAndPad';
  258.         envMacPlusKbd:
  259.             aString := 'envMacPlusKbd';
  260.         envAExtendKbd:
  261.             aString := 'envAExtendKbd';
  262.         envStandADBKbd:
  263.             aString := 'envStandADBKbd';
  264.         OTHERWISE
  265.             aString := 'envUnknownKbd';
  266.     END;
  267.     DoToField('  keyboardType', @aString, bString);
  268.  
  269.     DoToField('  atDrvrVersNum', @aConfigRec.atDrvrVersNum, bInteger);
  270.     DoToField('  sysVRefNum', @aConfigRec.sysVRefNum, bInteger);
  271.     DoToField('  hasROM128K', @aConfigRec.hasROM128K, bBoolean);
  272.     DoToField('  hasHFS', @aConfigRec.hasHFS, bBoolean);
  273.     DoToField('  hasHierarchicalMenus', @aConfigRec.hasHierarchicalMenus, bBoolean);
  274.     DoToField('  hasScriptManager', @aConfigRec.hasScriptManager, bBoolean);
  275.     DoToField('  hasStyleTextEdit', @aConfigRec.hasStyleTextEdit, bBoolean);
  276.     DoToField('  hasSoundManager', @aConfigRec.hasSoundManager, bBoolean);
  277.     DoToField('  hasWaitNextEvent', @aConfigRec.hasWaitNextEvent, bBoolean);
  278.     DoToField('  hasSCSI', @aConfigRec.hasSCSI, bBoolean);
  279.     DoToField('  hasDesktopBus', @aConfigRec.hasDesktopBus, bBoolean);
  280.     DoToField('  hasAUX', @aConfigRec.hasAUX, bBoolean);
  281.     DoToField('  hasTempMem', @aConfigRec.hasTempMem, bBoolean);
  282.     DoToField('  has32BitQD', @aConfigRec.has32BitQD, bBoolean);
  283.     END;
  284.  
  285. {--------------------------------------------------------------------------------------------------}
  286. {$S MAUtilitiesRes}
  287.  
  288. PROCEDURE CopyStr255(VAR fmStr: Str255;
  289.                      toAddr: UNIV Ptr);
  290.  
  291.     BEGIN
  292.     BlockMove(@fmStr, toAddr, LENGTH(fmStr) + 1);
  293.     END;
  294.  
  295. {--------------------------------------------------------------------------------------------------}
  296. {$S MAUtilitiesRes}
  297.  
  298. PROCEDURE DefaultSize(VAR theSize: INTEGER);
  299.  
  300.     BEGIN
  301.     IF qNeedsScriptManager | gConfiguration.hasScriptManager THEN
  302.         BEGIN
  303.         IF theSize = GetDefFontSize THEN
  304.             theSize := 0;
  305.         END
  306.     ELSE IF qNeedsROM128K | gConfiguration.hasROM128K THEN
  307.         BEGIN
  308.         IF (theSize = IntegerPtr(kLMSysFontSize)^) THEN
  309.             theSize := 0;
  310.         END
  311.     ELSE IF theSize = 12 THEN                            { Guess }
  312.         theSize := 0;
  313.     END;
  314.  
  315. {--------------------------------------------------------------------------------------------------}
  316. {$S MAFile}
  317.  
  318. FUNCTION DeleteFile(namePtr: StringPtr;
  319.                     volRefnum: INTEGER): OSErr;
  320.  
  321.     VAR
  322.         hPB:                HParamBlockRec;
  323.         err:                OSErr;
  324.  
  325.     BEGIN
  326.     WITH hPB DO
  327.         BEGIN
  328.         ioNamePtr := namePtr;
  329.         ioVRefnum := volRefnum;
  330.         ioFVersNum := 0;
  331.         END;
  332.  
  333.     err := FillInDirID(@hPB);                            {to avoid PMSP}
  334.  
  335.     IF err = noErr THEN
  336.         err := PBHDelete(@hPB, FALSE);
  337.  
  338.     DeleteFile := err;
  339.     END;
  340.  
  341. {--------------------------------------------------------------------------------------------------}
  342. {$S MAUtilitiesRes}
  343.  
  344. PROCEDURE DisposIfHandle(aHandle: UNIV Handle);
  345.  
  346.     BEGIN
  347.     aHandle := DisposeIfHandle(aHandle);
  348.     END;
  349.  
  350. {--------------------------------------------------------------------------------------------------}
  351. {$S MAUtilitiesRes}
  352.  
  353. FUNCTION DisposeIfHandle(aHandle: UNIV Handle): Handle;
  354.  
  355.     CONST
  356.         resourceBit         = 5;
  357.         initVal             = $D3;                        { odd at all byte boundaries }
  358.  
  359.     VAR
  360.         handleBits:         SignedByte;
  361.  
  362.     BEGIN
  363.     DisposeIfHandle := NIL;                             { For convenience of caller }
  364.  
  365.     IF aHandle <> NIL THEN
  366.         BEGIN
  367.         IF qDebug THEN
  368.             BEGIN
  369.             { Test handlehood }
  370.             IF IsHandle(aHandle) THEN
  371.                 BEGIN
  372.                 handleBits := GetHandleBits(aHandle);
  373.                 IF MemError <> noErr THEN
  374.                     BEGIN
  375.                     WriteLn('Handle was so bad I couldn''t even get the handle bits!');
  376.                     WrLblHexLongint('Bad Handle', longint(aHandle));
  377.                     WriteLn;
  378.                     ProgramBreak('');
  379.                     END
  380.                 ELSE IF IsHandlePurged(aHandle) THEN    { h might have been purged }
  381.                     BEGIN
  382.                     DisposHandle(aHandle);
  383.                     END
  384.                 ELSE IF BTST(handleBits, resourceBit) THEN
  385.                     BEGIN
  386.                     WriteLn('Trying to dispose a resource handle');
  387.                     WrLblHexLongint('Bad Handle', longint(aHandle));
  388.                     WriteLn;
  389.                     ProgramBreak('');
  390.                     END
  391.                 ELSE
  392.                     BEGIN
  393.                     { Set the handle contents to a real nice value for any dangling pointerciples }
  394.                     BlockSet(aHandle^, GetHandleSize(aHandle), initVal);
  395.                     DisposHandle(aHandle);
  396.                     END;
  397.                 END
  398.             ELSE
  399.                 BEGIN
  400.                 IF VerboseIsHandle(aHandle) THEN;        { Get the diagnosis printed }
  401.                 WriteLn('Trying to dispose an invalid handle');
  402.                 WrLblHexLongint('Bad Handle', longint(aHandle));
  403.                 WriteLn;
  404.                 ProgramBreak('');
  405.                 END;
  406.             END
  407.         ELSE
  408.             DisposHandle(aHandle);
  409.         END;
  410.     END;
  411.  
  412. {--------------------------------------------------------------------------------------------------}
  413. {$S MAUtilitiesRes}
  414.  
  415. PROCEDURE DisposIfPtr(aPtr: UNIV Ptr);
  416.  
  417.     BEGIN
  418.     aPtr := DisposeIfPtr(aPtr);
  419.     END;
  420.  
  421. {--------------------------------------------------------------------------------------------------}
  422. {$S MAUtilitiesRes}
  423.  
  424. FUNCTION DisposeIfPtr(aPtr: UNIV Ptr): Ptr;
  425.  
  426.     CONST
  427.         resourceBit         = 5;
  428.         initVal             = $D5;                        { odd at all byte boundaries }
  429.  
  430.     BEGIN
  431.     DisposeIfPtr := NIL;                                { For convenience of caller }
  432.  
  433.     IF aPtr <> NIL THEN
  434.         BEGIN
  435.         IF qDebug THEN
  436.             BEGIN
  437.             { Test pointerhood, ??? Shouldn't we have a real test here? }
  438.             IF (NOT Odd(Ord(aPtr))) THEN
  439.                 BEGIN
  440.                 BlockSet(aPtr, GetPtrSize(aPtr), initVal);
  441.                 DisposPtr(aPtr);
  442.                 END
  443.             ELSE
  444.                 BEGIN
  445.                 WriteLn('Trying to dispose an invalid pointer');
  446.                 WrLblHexLongint('Bad Pointer', longint(aPtr));
  447.                 WriteLn;
  448.                 ProgramBreak('');
  449.                 END;
  450.             END
  451.         ELSE
  452.             DisposPtr(aPtr);
  453.         aPtr := NIL;
  454.         END;
  455.     END;
  456.  
  457. {--------------------------------------------------------------------------------------------------}
  458.  
  459. FUNCTION EqualBlocks(first, second: UNIV Ptr;
  460.                      theSize: INTEGER): Boolean;
  461.     EXTERNAL;
  462.  
  463. {--------------------------------------------------------------------------------------------------}
  464. {$S MAUtilitiesRes}
  465.  
  466. PROCEDURE EachWMgrWindowDo(PROCEDURE DoToWMgrWindow(theWMgrWindow: WindowPtr));
  467.  
  468.     VAR
  469.         aWindowPtr:         WindowPtr;
  470.  
  471.     BEGIN
  472.     aWindowPtr := GetWindowList;
  473.     WHILE (aWindowPtr <> NIL) DO
  474.         BEGIN
  475.         DoToWMgrWindow(aWindowPtr);
  476.         aWindowPtr := WindowPtr(WindowPeek(aWindowPtr)^.nextWindow);
  477.         END;
  478.     END;
  479.  
  480. {--------------------------------------------------------------------------------------------------}
  481. {$S MAUtilitiesRes}
  482.  
  483. FUNCTION FindWindowBefore(theWindow: WindowPtr): WindowPtr;
  484. { returns the window just before a given window.  Returns nil if the given window is frontmost or
  485.   not found. }
  486.  
  487.     PROCEDURE DoToWMgrWindow(theWMgrWindow: WindowPtr);
  488.  
  489.         BEGIN
  490.         IF WindowPtr(WindowPeek(theWMgrWindow)^.nextWindow) = theWindow THEN
  491.             BEGIN
  492.             FindWindowBefore := theWMgrWindow;
  493.             exit(FindWindowBefore);
  494.             END;
  495.         END;
  496.  
  497.     BEGIN
  498.     FindWindowBefore := NIL;
  499.     EachWMgrWindowDo(DoToWMgrWindow);
  500.     END;
  501.  
  502. {--------------------------------------------------------------------------------------------------}
  503. {$S MAFile}
  504.  
  505. FUNCTION FileModDate(name: Str255;
  506.                      volRefnum: INTEGER): longint;
  507.  
  508.     VAR
  509.         pb:                 HParamBlockRec;
  510.  
  511.     BEGIN
  512.     IF GetFileInfo(name, volRefnum, pb) = noErr THEN
  513.         FileModDate := pb.ioFlMdDat
  514.     ELSE
  515.         FileModDate := 0;
  516.     END;
  517.  
  518. {--------------------------------------------------------------------------------------------------}
  519.  
  520. PROCEDURE FieldToString(theData: Ptr;
  521.                         fieldType: INTEGER;
  522.                         VAR theString: Str255);
  523.     EXTERNAL;
  524.  
  525. {--------------------------------------------------------------------------------------------------}
  526. {$S MAFile}
  527.  
  528. FUNCTION FillInDirID(pb: HParmBlkPtr): OSErr;
  529.  
  530.     BEGIN
  531.     FillInDirID := GetDirID(pb^.ioVRefnum, pb^.ioDirID);
  532.     END;
  533.  
  534. {--------------------------------------------------------------------------------------------------}
  535. {$S MAUtilitiesRes}
  536.  
  537. FUNCTION GetActualJustification(justification: INTEGER): INTEGER;
  538.  
  539.     BEGIN
  540.     IF justification = teJustSystem THEN                { actually teJustLeft }
  541.         BEGIN
  542.         IF qNeedsScriptManager | gConfiguration.hasScriptManager THEN
  543.             GetActualJustification := GetSysJust
  544.         ELSE IF qNeedsROM128K | gConfiguration.hasROM128K THEN
  545.             GetActualJustification := IntegerPtr(kLMTESysJust)^
  546.         ELSE
  547.             GetActualJustification := teJustLeft;
  548.         END
  549.     ELSE
  550.         GetActualJustification := justification;
  551.     END;
  552.  
  553. {--------------------------------------------------------------------------------------------------}
  554. {$S MAFile}
  555.  
  556. FUNCTION GetDirID(VAR vRefnum: INTEGER;
  557.                   VAR dirID: longint): OSErr;
  558.  
  559.     VAR
  560.         pb:                 WDPBRec;
  561.  
  562.     BEGIN
  563.     IF qNeedsROM128K | gConfiguration.hasHFS THEN
  564.         BEGIN
  565.         WITH pb DO
  566.             BEGIN
  567.             ioNamePtr := NIL;
  568.             ioVRefnum := vRefnum;
  569.             ioWDIndex := 0;
  570.             ioWDProcID := 0;
  571.             ioWDVRefnum := vRefnum;
  572.             END;
  573.         GetDirID := PBGetWDInfo(@pb, FALSE);
  574.         vRefnum := pb.ioWDVRefnum;
  575.         dirID := pb.ioWDDirID;
  576.         END
  577.     ELSE
  578.         BEGIN
  579.         dirID := 0;
  580.         GetDirID := noErr;
  581.         END;
  582.     END;
  583.  
  584. {--------------------------------------------------------------------------------------------------}
  585. {$S MAFile}
  586.  
  587. FUNCTION GetFileInfo(name: Str255;
  588.                      volRefnum: INTEGER;
  589.                      VAR info: HParamBlockRec): OSErr;
  590.  
  591.     VAR
  592.         err:                OSErr;
  593.  
  594.     BEGIN
  595.     WITH info DO
  596.         BEGIN
  597.         ioNamePtr := @name;
  598.         ioVRefnum := volRefnum;
  599.         ioFVersNum := 0;
  600.         ioFDirIndex := 0;
  601.         END;
  602.     err := FillInDirID(@info);
  603.     IF err = noErr THEN
  604.         err := PBHGetFInfo(@info, FALSE);
  605.     GetFileInfo := err;
  606.     END;
  607.  
  608. {--------------------------------------------------------------------------------------------------}
  609. {$S MAUtilitiesRes}
  610.  
  611. FUNCTION GetFontNum(fontName: Str255): INTEGER;
  612.  
  613.     VAR
  614.         fontNum:            INTEGER;
  615.  
  616.     BEGIN
  617.     UprString(fontName, FALSE);
  618.     IF fontName = kSysFontName THEN
  619.         BEGIN
  620.         IF qNeedsScriptManager | gConfiguration.hasScriptManager THEN
  621.             fontNum := GetSysFont
  622.         ELSE
  623.             fontNum := systemFont;
  624.         END
  625.     ELSE IF fontName = kApplFontName THEN
  626.         BEGIN
  627.         IF qNeedsScriptManager | gConfiguration.hasScriptManager THEN
  628.             fontNum := GetAppFont
  629.         ELSE
  630.             fontNum := applFont;
  631.         END
  632.     ELSE
  633.         GetFNum(fontName, fontNum);
  634.     GetFontNum := fontNum;
  635.     END;
  636.  
  637. {--------------------------------------------------------------------------------------------------}
  638. {$S MAUtilitiesRes}                                     {Must be in Main segment and cannot call to
  639.                                                          any other segment.}
  640.  
  641. FUNCTION GetHandleBits(h: Handle): SignedByte;
  642.  
  643.     BEGIN
  644.     IF qNeedsROM128K | gConfiguration.hasROM128K THEN
  645.         GetHandleBits := HGetState(h)
  646.     ELSE
  647.         GetHandleBits := SignedBytePtr(h)^;
  648.     END;
  649.  
  650. {--------------------------------------------------------------------------------------------------}
  651. {$IFC NOT qNeedsColorQD}                                { Becomes an inline if we know the machine
  652.                                                          has color QD }
  653. {$S MAUtilitiesRes}
  654.  
  655. PROCEDURE GetIfBkColor(VAR aColor: RGBColor);
  656.  
  657.     CONST
  658.         BlackBit            = 5;
  659.         YellowBit            = 6;
  660.         MagentaBit            = 7;
  661.         CyanBit             = 8;
  662.  
  663.     VAR
  664.         oldColor:            longint;
  665.  
  666.     BEGIN
  667.     IF qNeedsColorQD | gConfiguration.hasColorQD THEN
  668.         GetBackColor(aColor)
  669.     ELSE
  670.         BEGIN                                            { Map old, dumb CMYB system to RGB color }
  671.         {[f-]}
  672.         (*                        xxxxxxx C.MY B rgb w b    = RGB
  673.         blackColor        =  33 = 0000000 0.00 1 000 0 1    = 000
  674.         whiteColor        =  30 = 0000000 0.00 0 111 1 0    = 111
  675.         redColor        = 205 = 0000000 0.11 0 011 0 1    = 100
  676.         greenColor        = 341 = 0000000 1.01 0 101 0 1    = 010
  677.         blueColor        = 409 = 0000000 1.10 0 110 0 1    = 001
  678.         cyanColor        = 273 = 0000000 1.00 0 100 0 1    = 011
  679.         magentaColor    = 137 = 0000000 0.10 0 010 0 1    = 101
  680.         yellowColor     =  69 = 0000000 0.01 0 001 0 1    = 110
  681.         *)
  682.         {[f+]}
  683.  
  684.         oldColor := thePort^.bkColor;                    { Fetch old color }
  685.         aColor := gRGBBlack;                            { Prime returned color to black }
  686.         IF BTST(oldColor, BlackBit) THEN                { If color isn't black, force CMY = 111 }
  687.             oldColor := BOR(oldColor, $1C0);
  688.         IF NOT BTST(oldColor, CyanBit) THEN             { Absence of cyan = presence of red }
  689.             aColor.red := $FFFF;
  690.         IF NOT BTST(oldColor, MagentaBit) THEN            { Absence of magenta = presence of green }
  691.             aColor.green := $FFFF;
  692.         IF NOT BTST(oldColor, YellowBit) THEN            { Absence of yellow = presence of blue }
  693.             aColor.blue := $FFFF;
  694.         END;
  695.     END;
  696. {$ENDC}
  697.  
  698. {--------------------------------------------------------------------------------------------------}
  699. {$IFC NOT qNeedsColorQD}                                { Becomes an inline if we know the machine
  700.                                                          has color QD }
  701. {$S MAUtilitiesRes}
  702.  
  703. PROCEDURE GetIfColor(VAR aColor: RGBColor);
  704.  
  705.     CONST
  706.         BlackBit            = 5;
  707.         YellowBit            = 6;
  708.         MagentaBit            = 7;
  709.         CyanBit             = 8;
  710.  
  711.     VAR
  712.         oldColor:            longint;
  713.  
  714.     BEGIN
  715.     IF qNeedsColorQD | gConfiguration.hasColorQD THEN
  716.         GetForeColor(aColor)
  717.     ELSE
  718.         BEGIN                                            { Map old, dumb CMYB system to RGB color }
  719.   {   xxxxxxx C.MY B rgb w b = RGB
  720.   blackColor  =  33 = 0000000 0.00 1 000 0 1 = 000
  721.   whiteColor  =  30 = 0000000 0.00 0 111 1 0 = 111
  722.   redColor = 205 = 0000000 0.11 0 011 0 1 = 100
  723.   greenColor  = 341 = 0000000 1.01 0 101 0 1 = 010
  724.   blueColor  = 409 = 0000000 1.10 0 110 0 1 = 001
  725.   cyanColor  = 273 = 0000000 1.00 0 100 0 1 = 011
  726.   magentaColor = 137 = 0000000 0.10 0 010 0 1 = 101
  727.   yellowColor  =  69 = 0000000 0.01 0 001 0 1 = 110
  728.   }
  729.         oldColor := thePort^.fgColor;                    { Fetch old color }
  730.         aColor := gRGBBlack;                            { Prime returned color to black }
  731.         IF BTST(oldColor, BlackBit) THEN                { If color isn't black, force CMY = 111 }
  732.             oldColor := BOR(oldColor, $1C0);
  733.         IF NOT BTST(oldColor, CyanBit) THEN             { Absence of cyan = presence of red }
  734.             aColor.red := $FFFF;
  735.         IF NOT BTST(oldColor, MagentaBit) THEN            { Absence of magenta = presence of green }
  736.             aColor.green := $FFFF;
  737.         IF NOT BTST(oldColor, YellowBit) THEN            { Absence of yellow = presence of blue }
  738.             aColor.blue := $FFFF;
  739.         END;
  740.     END;
  741. {$ENDC}
  742.  
  743. {--------------------------------------------------------------------------------------------------}
  744. {$S MAUtilitiesRes}
  745.  
  746. PROCEDURE GetPortFontInfo(fontNum: INTEGER;
  747.                           VAR fontName: Str255;
  748.                           VAR fontSize: INTEGER);
  749.  
  750.     BEGIN
  751.     IF (fontNum = systemFont) | ((qNeedsROM128K | gConfiguration.hasROM128K) & (
  752.        (qNeedsScriptManager | gConfiguration.hasScriptManager) & (fontNum = GetSysFont)) |
  753.        (fontNum = IntegerPtr(kLMSysFontFam)^)) THEN
  754.         BEGIN
  755.         fontName := kSysFontName;
  756.         DefaultSize(fontSize);
  757.         END
  758.  
  759.     ELSE IF (fontNum = applFont) | (((qNeedsScriptManager | gConfiguration.hasScriptManager) &
  760.             (fontNum = GetAppFont)) | (fontNum = IntegerPtr(kLMApFontID)^)) THEN
  761.         BEGIN
  762.         fontName := kApplFontName;
  763.         DefaultSize(fontSize);
  764.         END
  765.  
  766.     ELSE
  767.         GetFontName(fontNum, fontName);
  768.     END;
  769.  
  770. {--------------------------------------------------------------------------------------------------}
  771. {$Push}
  772. {$MC68020-}
  773. {$S Main}
  774.  
  775. PROCEDURE LockHandleHigh(h: Handle);
  776.  
  777.     BEGIN
  778.     IF h <> NIL THEN
  779.         BEGIN
  780.         IF qDebug & NOT IsHandle(h) THEN
  781.             BEGIN
  782.             IF VerboseIsHandle(h) THEN;                 { Get the diagnosis printed }
  783.             ProgramBreak('In LockHandleHigh: not handed a handle');
  784.             END
  785.         ELSE
  786.             BEGIN
  787.             MoveHHi(h);                                 { ??? check MemErr ??? }
  788.             HLock(h);
  789.             END;
  790.         END;
  791.     END;
  792. {$Pop}
  793.  
  794. {--------------------------------------------------------------------------------------------------}
  795. {$Push}
  796. {$MC68020-}
  797. {$S MAUtilitiesRes}
  798.  
  799. FUNCTION GetTrapType(theTrap: INTEGER): TrapType;
  800.  
  801.     BEGIN
  802.     { OS traps start with A0, Tool with A8 or AA. }
  803.     IF BAND(theTrap, $0800) = 0 THEN                    { per D.A }
  804.         GetTrapType := OSTrap
  805.     ELSE
  806.         GetTrapType := ToolTrap;
  807.     END;
  808. {$Pop}
  809.  
  810. {--------------------------------------------------------------------------------------------------}
  811. { Nothing in this procedure can be allowed to fail }
  812. {$Push}
  813. {$MC68020-}
  814. {$S MAMiniInit}
  815.  
  816. PROCEDURE DoRealInitToolBox;
  817.  
  818.     VAR
  819.         aCursHandle:        CursHandle;
  820.  
  821.     BEGIN
  822.     InitGraf(@thePort);
  823.     InitFonts;
  824.     InitWindows;                                        { creates non-relocatable for the WM port }
  825.  
  826.     { _DON'T_ flush disk-inserted or MultiFinder™ events or you'll be sorry! }
  827.     FlushEvents(everyEvent - diskMask - app4Evt, 0);
  828.  
  829.     InitMenus;
  830.     TEInit;
  831.     InitDialogs(NIL);
  832.     aCursHandle := GetCursor(watchCursor);                { Watch should be in system file, but just
  833.                                                          in case… }
  834.  
  835.     InitCursor;                                         { !!! This forces an arrow cursor. Is there
  836.                                                          a way to reset the show/hide level and
  837.                                                          init all the cursor goo without having
  838.                                                          this visual glitch? ( the Finder™ sets the
  839.                                                          cursor to a watch when launching. It would
  840.                                                          be nice to stay that way until the app is
  841.                                                          ready for events. }
  842.     IF aCursHandle <> NIL THEN
  843.         SetCursor(aCursHandle^^);                        { Change cursor to watch }
  844.  
  845.     {$IFC qDebug}                                        { Enable pre and postcondition testing }
  846.     gPreCondition := TRUE;
  847.     gPostCondition := TRUE;
  848.     {$ENDC}
  849.  
  850.     { Find out just what kind of environment we're dealing with here }
  851.     DefineConfiguration(gConfiguration);
  852.  
  853.     { Init the stuff that MATextBox uses }
  854.     gMATextBoxTE := NIL;
  855.     gTEDefaultWordBreak := NIL;
  856.  
  857.     SetRGBColor(gRGBBlack, 0, 0, 0);
  858.     SetRGBColor(gRGBWhite, $FFFF, $FFFF, $FFFF);
  859.  
  860.     { -1 = $FFFFFFFF, the largest 32 bit address.  Our routine StripLong uses a pre-stripped
  861.     address gStrippedAddress to avoid the yucky MPW glue. }
  862.     gStrippedAddress := StripAddress(Ptr( - 1));
  863.  
  864.     { !!! I hate to have to allocate this memory here.    Is there a better way to encapsulate
  865.     this and defer the allocation until later.    Many routines touch the region (Even after
  866.     InvalidateCursor was implemented) }
  867.     gCursorRgn := NewRgn;                                { Hope it doesn't fail. Really isn't likely
  868.                                                          to though. }
  869.  
  870.     IF qNeedsScriptManager | gConfiguration.hasScriptManager THEN
  871.         gMBarHeight := GetMBarHeight
  872.     ELSE IF qNeedsROM128K | gConfiguration.hasROM128K THEN
  873.         gMBarHeight := GetLMMBarHeight
  874.     ELSE
  875.         gMBarHeight := 20;                                { Guess }
  876.  
  877.     {$IFC qDebug OR qInspector}
  878.     gFieldToStrRtn := @StdFieldToString;
  879.     {$EndC}
  880.  
  881.     gBoolString[TRUE] := 'TRUE';
  882.     gBoolString[FALSE] := 'FALSE';
  883.     gDeadStripSuppression := FALSE;
  884.     gCreateWithTemplates := gDeadStripSuppression;        { for compatibility with Dave W. class notes
  885.                                                          }
  886.     { The refnum where the application's resources should be found }
  887.     gApplicationRefNum := CurResFile;
  888.  
  889.     gToolBoxInitialized := TRUE;
  890.     END;
  891. {$Pop}
  892.  
  893. {--------------------------------------------------------------------------------------------------}
  894. { Nothing in this procedure can be allowed to fail }
  895. {$Push}
  896. {$MC68020-}
  897. {$S Main}                                                { This procedure is intended to be in "Main"
  898.                                                          which is already loaded }
  899.  
  900. PROCEDURE _DataInit;                                    { Routine in the A5 globals initializer }
  901.     EXTERNAL;
  902.  
  903. PROCEDURE InitToolBox;
  904.  
  905.     CONST
  906.         kBreathingRoom        = 1024;                     { Amount of heap space needed for init }
  907.  
  908.     VAR
  909.         totalSize:            Size;
  910.         contigSize:         Size;
  911.         h:                    Handle;
  912.  
  913.     PROCEDURE FailedInitToolBox;
  914.  
  915.         BEGIN
  916.         IF qDebug THEN
  917.             DebugStr('Not enough room to init ToolBox Managers');
  918.         ExitToShell;                                    {??? any good way to signal this to the user
  919.                                                          ???}
  920.         END;
  921.  
  922.     BEGIN
  923.     { the heap and stack don't overlap. So there's enough room to init the managers.
  924.     Make sure that the MAMiniInit Segment can be loaded and that there's still a little
  925.     Room after that. }
  926.  
  927.     UnloadSeg(@_DataInit);                                { Toss some ballast }
  928.  
  929.     { "MAMain" this is MacApp's own code that must be resident… even before/during the UMemory startup.
  930.     GetNamedResource will call RsrvMem which locates the handle as low in memory as possible.
  931.     We will then lock it there… just like "Main"}
  932.     SetResLoad(FALSE);
  933.     h := GetNamedResource('CODE', 'MAMain');
  934.     SetResLoad(TRUE);
  935.     IF (h <> NIL) THEN
  936.         ResrvMem(SizeResource(h));
  937.     h := GetNamedResource('CODE', 'MAMain');
  938.     IF (h <> NIL) THEN
  939.         HLock(h)
  940.     ELSE
  941.         FailedInitToolBox;
  942.  
  943.     h := GetNamedResource('CODE', 'MAMiniInit');
  944.     IF (h <> NIL) THEN
  945.         HLock(h)
  946.     ELSE
  947.         FailedInitToolBox;
  948.  
  949.     { Attempt to ensure that there is going to be kBreathingRoom bytes available in the heap so that
  950.     when the actual toolbox managers are initialized there is a significantly reduced chance that
  951.     they will express their displeasure with us through SysErr -25 or -2.  If the space is not
  952.     currently available in the zone as shown by PurgeSpace then attempting to allocate it will let
  953.     growzoneproc operate and grow the zone a little, as necessary.  If, after that, we haven't been
  954.     able to get the breathing room we desire then just give up and fade silently away. (Like the old
  955.     soldier, not the old executive). }
  956.  
  957.     PurgeSpace(totalSize, contigSize);
  958.  
  959.     IF totalSize >= kBreathingRoom THEN
  960.         DoRealInitToolBox
  961.     ELSE
  962.         BEGIN
  963.         h := NewHandle(kBreathingRoom);
  964.         IF h <> NIL THEN                             { get the grow space }
  965.             BEGIN
  966.             DisposHandle(h);
  967.             DoRealInitToolBox;
  968.             END
  969.         ELSE
  970.             FailedInitToolBox;                        { Give up }
  971.         END;
  972.     END;
  973. {$Pop}
  974.  
  975. {--------------------------------------------------------------------------------------------------}
  976. { Nothing in this procedure can be allowed to fail }
  977. {$Push}
  978. {$MC68020-}
  979. {$S MAMiniInit}
  980.  
  981. FUNCTION ValidateConfiguration(configuration: ConfigRecord): Boolean;
  982.  
  983.     VAR
  984.         isSupported:        Boolean;
  985.  
  986.     BEGIN
  987.     { Run the gauntlet of support tests using the conditionally set constants.
  988.     If any single test fails then the app is considered unsupported on this machine.  }
  989.  
  990.     isSupported := TRUE;
  991.  
  992.     IF qNeedsScriptManager THEN
  993.         isSupported := isSupported & configuration.hasScriptManager;
  994.  
  995.     IF qNeedsROM128K THEN
  996.         isSupported := isSupported & configuration.hasROM128K;
  997.  
  998.     IF qNeedsHierarchicalMenus THEN
  999.         isSupported := isSupported & configuration.hasHierarchicalMenus;
  1000.  
  1001.     IF qNeedsStyleTextEdit THEN
  1002.         isSupported := isSupported & configuration.hasStyleTextEdit;
  1003.  
  1004.     IF qNeedsWaitNextEvent THEN
  1005.         isSupported := isSupported & configuration.hasWaitNextEvent;
  1006.  
  1007.     IF qNeedsColorQD THEN
  1008.         isSupported := isSupported & configuration.hasColorQD;
  1009.  
  1010.     IF qNeedsMC68020 THEN
  1011.         isSupported := isSupported & ((configuration.processor <> env68000) &
  1012.                        (configuration.processor <> env68010));
  1013.  
  1014.     IF qNeedsMC68030 THEN
  1015.         isSupported := isSupported & ((configuration.processor <> env68000) &
  1016.                        (configuration.processor <> env68010) & (configuration.processor <>
  1017.                        env68020));
  1018.  
  1019.     IF qNeedsFPU THEN
  1020.         isSupported := isSupported & configuration.hasFPU;
  1021.  
  1022.     ValidateConfiguration := isSupported;
  1023.     END;
  1024. {$Pop}
  1025.  
  1026. {--------------------------------------------------------------------------------------------------}
  1027. { Nothing in this procedure can be allowed to fail }
  1028. {$Push}
  1029. {$MC68020-}
  1030. {$S MAMiniInit}
  1031.  
  1032. PROCEDURE DefineConfiguration(VAR configuration: ConfigRecord);
  1033.  
  1034.     CONST
  1035.  
  1036.         {Masks for the HwCfgFlags}
  1037.         mSCSIPort            = $8000;
  1038.         mDesktopBus         = $0400;
  1039.         mHasAUX             = $0200;
  1040.  
  1041.         { Test that DTS says is OK for 32 bit QD.  It is an internal trap that is only implemented
  1042.         if QD32 is installed.    }
  1043.         _MA32BitQD            = $AB03;
  1044.  
  1045.     VAR
  1046.         kludge:             ^SysEnvRec;
  1047.         result:             OSErr;
  1048.  
  1049.     BEGIN
  1050.     kludge := @configuration;
  1051.     result := SysEnvirons(1, kludge^);                    {Version 1 shouldn't fail}
  1052.  
  1053.     WITH configuration DO
  1054.         BEGIN
  1055.         hasDesktopBus := BAND(GetHwCfgFlags, mDesktopBus) > 0;
  1056.         hasSCSI := BAND(GetHwCfgFlags, mSCSIPort) > 0;
  1057.         hasAUX := BAND(GetHwCfgFlags, mHasAUX) > 0;
  1058.         hasROM128K := machineType > envMac;
  1059.         IF hasROM128K THEN
  1060.             hasHFS := TRUE
  1061.         ELSE
  1062.             hasHFS := GetFSFCBLen > 0;
  1063.         hasHierarchicalMenus := hasROM128K & TrapExists(_PopUpMenuSelect);
  1064.         hasScriptManager := hasROM128K & TrapExists(_ScriptUtil);
  1065.         hasStyleTextEdit := systemVersion >= $600;
  1066.         hasSoundManager := hasROM128K & TrapExists(_SndDoCommand);
  1067.         hasWaitNextEvent := hasROM128K & TrapExists(_WaitNextEvent);
  1068.         hasTempMem := TrapExists(_OSDispatch);
  1069.         has32BitQD := TrapExists(_MA32BitQD);
  1070.         END;
  1071.     END;
  1072. {$Pop}
  1073.  
  1074. {--------------------------------------------------------------------------------------------------}
  1075. { Nothing in this procedure can be allowed to fail }
  1076. {$Push}
  1077. {$MC68020-}
  1078. {$S Main}                                                { Must be in main segment as it is called in
  1079.                                                          early initialization AND in MacAppAlert }
  1080.  
  1081. PROCEDURE PullApplicationToFront;
  1082.  
  1083.     VAR
  1084.         theEvent:            EventRecord;
  1085.         i:                    INTEGER;
  1086.  
  1087.     BEGIN
  1088.     { The "Programmer's guide to MultiFinder™ says make an event call several times.
  1089.     I guess 3 calls counts as several.    Also, it says call GetNextEvent but we don't
  1090.     want to lose events on the floor so we use EventAvail since it seems to work OK }
  1091.     FOR i := 1 TO 3 DO
  1092.         IF EventAvail(everyEvent, theEvent) THEN;
  1093.     END;
  1094. {$Pop}
  1095.  
  1096. {--------------------------------------------------------------------------------------------------}
  1097.  
  1098. {$S MAUtilitiesRes}
  1099.  
  1100. FUNCTION IsFreeHandle(h: UNIV Handle): Boolean;
  1101. { Walk the free-list looking for the given handle }
  1102.  
  1103.     VAR
  1104.         applZone:            THz;
  1105.         currHandle:         Handle;
  1106.  
  1107.     BEGIN
  1108.     IsFreeHandle := FALSE;
  1109.     applZone := ApplicZone;
  1110.     currHandle := Handle(applZone^.hFstFree);
  1111.     WHILE (currHandle <> NIL) DO
  1112.         BEGIN
  1113.         IF currHandle = h THEN
  1114.             BEGIN
  1115.             IsFreeHandle := TRUE;
  1116.             LEAVE;
  1117.             END;
  1118.         currHandle := Handle(currHandle^);
  1119.         END;
  1120.  
  1121.     END;
  1122.  
  1123. {--------------------------------------------------------------------------------------------------}
  1124.  
  1125. {$S MAUtilitiesRes}
  1126.  
  1127. FUNCTION TestRecoverHandle(masterPointer: Ptr;
  1128.                            h: UNIV Handle): Boolean;
  1129.  
  1130. { TestRecoverHandle determines if the given masterPointer recovers via RecoverHandle to be the given
  1131. handle h. Since RecoverHandle fails if h is from a heap other than the current heap, we need to set
  1132. the zone to be the handle's zone before calling RecoverHandle. }
  1133.  
  1134.     VAR
  1135.         itsZone,                                        { the handle's zone }
  1136.         currentZone:        THz;                        { the current zone (don't assume ApplicZone)
  1137.                                                          }
  1138.         restoreZone:        Boolean;                    { flag whether to restore zone }
  1139.  
  1140.     BEGIN
  1141.     TestRecoverHandle := FALSE;
  1142.  
  1143.     { Test handle's Zone - if it comes from a different zone, then RecoverHandle won't work,
  1144.     in that case, set the current zone to be the handle's zone }
  1145.  
  1146.     itsZone := HandleZone(h);                            { get the handle's zone }
  1147.     IF MemError = noErr THEN
  1148.         BEGIN
  1149.         currentZone := GetZone;                         { get the current zone }
  1150.         IF itsZone = currentZone THEN                    { Are zones the same? }
  1151.             restoreZone := FALSE                        { …yes, so set flag to not restore }
  1152.         ELSE
  1153.             BEGIN
  1154.             restoreZone := TRUE;                        { …no, so set flag to restore zone }
  1155.             SetZone(itsZone);                            { and set the zone to be the handle's zone }
  1156.             END;
  1157.  
  1158.         TestRecoverHandle := RecoverHandle(masterPointer) = Handle(h);
  1159.  
  1160.         IF restoreZone THEN                             { restore the zone if the flag is set }
  1161.             SetZone(currentZone);
  1162.         END;
  1163.     END;
  1164.  
  1165. {--------------------------------------------------------------------------------------------------}
  1166.  
  1167. {$S MAUtilitiesRes}
  1168.  
  1169. FUNCTION IsHandle(h: UNIV Handle): Boolean;
  1170. { Returns true if handle appears valid. }
  1171.  
  1172.     VAR
  1173.         masterPointer:        Ptr;
  1174.  
  1175.     BEGIN
  1176.     IsHandle := FALSE;
  1177.  
  1178.     IF
  1179.     { Test handle NILness }
  1180.       (h <> NIL)
  1181.     { Test handle Oddness }
  1182.       & NOT Odd(Ord(h)) THEN
  1183.         BEGIN
  1184.         masterPointer := Ptr(StripLong(h^));
  1185.         IsHandle :=
  1186.         { Test master pointer Oddness }
  1187.           (NOT Odd(Ord(masterPointer)))
  1188.         { Not Purged… does it recover? }
  1189.           & (((masterPointer <> NIL) & (TestRecoverHandle(masterPointer, h)))
  1190.         { Purged }
  1191.           | (masterPointer = NIL));
  1192.         END;
  1193.     END;
  1194.  
  1195. {--------------------------------------------------------------------------------------------------}
  1196.  
  1197. {$S MAUtilitiesRes}
  1198.  
  1199. FUNCTION IsHandleLocked(h: UNIV Handle): Boolean;
  1200. { Returns lockState of h. }
  1201.  
  1202.     CONST
  1203.         lockBit             = 7;
  1204.  
  1205.     VAR
  1206.         handleBits:         SignedByte;
  1207.  
  1208.     BEGIN
  1209.     handleBits := GetHandleBits(h);
  1210.     IF MemError <> noErr THEN                            { h might have been purged }
  1211.         IsHandleLocked := FALSE
  1212.     ELSE
  1213.         IsHandleLocked := BTST(handleBits, lockBit);
  1214.     END;
  1215.  
  1216. {--------------------------------------------------------------------------------------------------}
  1217.  
  1218. {$IFC qDebug}
  1219. {$S MAUtilitiesRes}
  1220.  
  1221. FUNCTION IsHandlePurged(h: UNIV Handle): Boolean;
  1222. { Returns purgeState of h. }
  1223.  
  1224.     BEGIN
  1225.     IF qDebug & NOT IsHandle(h) THEN
  1226.         BEGIN
  1227.         IF VerboseIsHandle(h) THEN;                     { Get the diagnosis printed }
  1228.         ProgramBreak('IsHandlePurged was not handed a handle, pretty handy, eh?');
  1229.         IsHandlePurged := TRUE;                         { !!! What is a decent result. shouldn't
  1230.                                                          developer just signal failure from the
  1231.                                                          debugger. We need to force the issue }
  1232.         END
  1233.     ELSE
  1234.         IsHandlePurged := h^ = NIL;
  1235.     END;
  1236. {$EndC}
  1237.  
  1238. {--------------------------------------------------------------------------------------------------}
  1239. {$S MAUtilitiesRes}
  1240.  
  1241. FUNCTION LengthRect(r: Rect;
  1242.                     vhs: VHSelect): INTEGER;
  1243.  
  1244.     BEGIN
  1245.     WITH r DO
  1246.         LengthRect := botRight.vh[vhs] - topLeft.vh[vhs];
  1247.     END;
  1248.  
  1249. {--------------------------------------------------------------------------------------------------}
  1250. {$S MAUtilitiesRes}
  1251.  
  1252. FUNCTION LongerSide(VAR r: Rect): VHSelect;
  1253.  
  1254.     BEGIN
  1255.     WITH r DO
  1256.         IF (bottom - top) >= (left - right) THEN
  1257.             LongerSide := v
  1258.         ELSE
  1259.             LongerSide := h;
  1260.     END;
  1261.  
  1262. {--------------------------------------------------------------------------------------------------}
  1263. {$S MADebug}
  1264.  
  1265. PROCEDURE LIntToHex(decNumber: UNIV longint;
  1266.                     VAR hexNumber: String8;
  1267.                     noOfDigits: INTEGER);
  1268.  
  1269.     VAR
  1270.         i:                    INTEGER;
  1271.  
  1272.     BEGIN
  1273.     noOfDigits := Min(noOfDigits, 8);
  1274.     hexNumber[0] := CHR(noOfDigits);
  1275.     FOR i := noOfDigits DOWNTO 1 DO
  1276.         BEGIN
  1277.         hexNumber[i] := kHexDigits[BAND(decNumber, 15) + 1];
  1278.         decNumber := BSR(decNumber, 4);
  1279.         END;
  1280.     END;
  1281.  
  1282. {--------------------------------------------------------------------------------------------------}
  1283. {$S MAUtilitiesRes}
  1284.  
  1285. FUNCTION LowerChar(ch: CHAR): CHAR;
  1286.  
  1287.     BEGIN
  1288.     IF (ch >= 'A') & (ch <= 'Z') THEN
  1289.         LowerChar := CHR(Ord(ch) + 32)
  1290.     ELSE
  1291.         LowerChar := ch;
  1292.     END;
  1293.  
  1294. {--------------------------------------------------------------------------------------------------}
  1295. {$S MAUtilitiesRes}
  1296.  
  1297. PROCEDURE LowerStr255(VAR s: Str255);
  1298.  
  1299.     VAR
  1300.         i:                    INTEGER;
  1301.  
  1302.     BEGIN
  1303.     FOR i := 1 TO LENGTH(s) DO
  1304.         IF (s[i] IN ['A'..'Z']) THEN
  1305.             s[i] := CHR(Ord(s[i]) + 32)
  1306.     END;
  1307.  
  1308. {--------------------------------------------------------------------------------------------------}
  1309. {$S MAUtilitiesRes}
  1310.  
  1311. FUNCTION MAUseResFile(refNum: INTEGER): INTEGER;
  1312. { UseResFile the newResFile and return the old CurResFile. }
  1313.  
  1314.     BEGIN
  1315.     MAUseResFile := CurResFile;
  1316.     UseResFile(refNum);
  1317.     END;
  1318.  
  1319. {--------------------------------------------------------------------------------------------------}
  1320. {$S MAUtilitiesRes}
  1321.  
  1322. FUNCTION MinMax(MinVal, expression, MaxVal: longint): longint;
  1323. {Returns the bounded minimum and maximum }
  1324.  
  1325.     BEGIN
  1326.     MinMax := Min(Max(expression, MinVal), MaxVal);
  1327.     END;
  1328.  
  1329. {--------------------------------------------------------------------------------------------------}
  1330. {$S MADebug}
  1331.  
  1332. PROCEDURE NumberToHex(theNumber: UNIV longint;
  1333.                       VAR hexString: Str255;
  1334.                       hexDigits: INTEGER);
  1335.  
  1336.     VAR
  1337.         tempString:         String8;
  1338.  
  1339.     BEGIN
  1340.     LIntToHex(theNumber, tempString, hexDigits);
  1341.     hexString := CONCAT('$', tempString);
  1342.     END;
  1343.  
  1344. {--------------------------------------------------------------------------------------------------}
  1345. {$S MADebug}
  1346.  
  1347. PROCEDURE PointerToHex(theNumber: UNIV longint;
  1348.                        VAR hexString: Str255;
  1349.                        hexDigits: INTEGER);
  1350.  
  1351.     VAR
  1352.         tempString:         String8;
  1353.  
  1354.     BEGIN
  1355.     IF theNumber = 0 THEN
  1356.         hexString := 'Nil'
  1357.     ELSE
  1358.         BEGIN
  1359.         LIntToHex(StripLong(theNumber), tempString, hexDigits);
  1360.         hexString := CONCAT('$', tempString);
  1361.         END;
  1362.     END;
  1363.  
  1364. {--------------------------------------------------------------------------------------------------}
  1365. {$S MAFile}
  1366.  
  1367. FUNCTION NumBlocks(numBytes: longint;
  1368.                    blkSize: longint): longint;
  1369.  
  1370.     BEGIN
  1371.     NumBlocks := (numBytes + blkSize - 1) DIV blkSize;
  1372.     END;
  1373.  
  1374. {--------------------------------------------------------------------------------------------------}
  1375. {$S MAFile}
  1376.  
  1377. FUNCTION MAOpenFile(name: Str255;
  1378.                     volRefnum: INTEGER;
  1379.                     openData, openRsrc: Boolean;
  1380.                     dataPerm, rsrcPerm: INTEGER;
  1381.                     VAR dataRefnum, rsrcRefnum: INTEGER): OSErr;
  1382.  
  1383.     VAR
  1384.         pb:                 HParamBlockRec;
  1385.         oldVRefnum:         INTEGER;
  1386.         result:             OSErr;
  1387.  
  1388.     PROCEDURE TestForError(err: OSErr);
  1389.  
  1390.         BEGIN
  1391.         IF err <> noErr THEN
  1392.             BEGIN
  1393.             MAOpenFile := err;
  1394.             exit(MAOpenFile);
  1395.             END;
  1396.         END;
  1397.  
  1398.     BEGIN
  1399.     {always open data fork, to establish that the file does exist}
  1400.     WITH pb DO
  1401.         BEGIN
  1402.         ioNamePtr := @name;
  1403.         ioVRefnum := volRefnum;
  1404.         ioVersNum := 0;
  1405.         ioPermssn := dataPerm;
  1406.         ioMisc := NIL;
  1407.         END;
  1408.     TestForError(FillInDirID(@pb));
  1409.  
  1410.     IF qNeedsROM128K | gConfiguration.hasHFS THEN
  1411.         result := PBHOpenDeny(@pb, FALSE)                { Try the shared volume open. }
  1412.     ELSE
  1413.         result := paramErr;
  1414.  
  1415.     IF result = paramErr THEN                            { Not on a shared volume, try HFS open. }
  1416.         BEGIN
  1417.         pb.ioPermssn := BAND(dataPerm, 3);
  1418.         result := PBHOpen(@pb, FALSE);
  1419.         END;
  1420.     TestForError(result);
  1421.  
  1422.     IF openData THEN
  1423.         dataRefnum := pb.ioRefnum
  1424.     ELSE
  1425.         BEGIN
  1426.         { we did not want the data fork open, so close it now }
  1427.         TestForError(FSClose(pb.ioRefnum));
  1428.         dataRefnum := kNoFileRefnum;
  1429.         END;
  1430.  
  1431.     IF openRsrc THEN
  1432.         BEGIN
  1433.         IF qNeedsROM128K | gConfiguration.hasROM128K THEN
  1434.             BEGIN
  1435.             rsrcRefnum := OpenRFPerm(name, volRefnum, BAND(rsrcPerm, 7));
  1436.             result := ResError;
  1437.             END
  1438.         ELSE
  1439.             BEGIN
  1440.             TestForError(GetVol(NIL, oldVRefnum));
  1441.             TestForError(SetVol(NIL, volRefnum));
  1442.  
  1443.             rsrcRefnum := OpenResFile(name);
  1444.  
  1445.             TestForError(SetVol(NIL, oldVRefnum));
  1446.             END;
  1447.  
  1448.         IF result <> noErr THEN
  1449.             rsrcRefnum := kNoFileRefnum;
  1450.  
  1451.         TestForError(result);
  1452.         END
  1453.     ELSE
  1454.         rsrcRefnum := kNoFileRefnum;
  1455.  
  1456.     MAOpenFile := noErr;
  1457.  
  1458.     END;
  1459.  
  1460. {--------------------------------------------------------------------------------------------------}
  1461. {$S MAUtilitiesRes}
  1462.  
  1463. VAR
  1464.     pSaveHText:         Handle;
  1465.     pMATextBoxHText:    Handle;
  1466.  
  1467. {$Push}
  1468. {$IFC qTrace} {$D+} {$ENDC}
  1469.  
  1470. PROCEDURE StdNoRect(verb: GrafVerb;
  1471.                     r: Rect);
  1472. { StdNoRect filters out the rect drawing calls. }
  1473.  
  1474.     BEGIN
  1475.     END;
  1476. {$Pop}
  1477.  
  1478. PROCEDURE MATextBox(text: Ptr;
  1479.                     itsLength: longint;
  1480.                     box: Rect;
  1481.                     itsJust: INTEGER;
  1482.                     autoWrap: Boolean;
  1483.                     wordBreak: ProcPtr;
  1484.                     eraseFirst: Boolean;
  1485.                     spaceForCaret: Boolean);
  1486.  
  1487.     CONST
  1488.         kTextBoxCaretSlopSize = 1;                        { Since TextBox uses TE to image the text,
  1489.                                                          we may need to adjust by 1 pixel. Reason:
  1490.                                                          TE draws beginning 1 pixel to the right to
  1491.                                                          allow for the insertion point (which we
  1492.                                                          won't have since this is drawn text, not
  1493.                                                          editable text).}
  1494.         kMaxTEChars         = 32000;                    { Actually TE suffers some other limitations
  1495.                                                          as well. Such as misbehaviour and or
  1496.                                                          bombing when the sum of the lineheights >
  1497.                                                          32k or a linewidth > 32k (overflows
  1498.                                                          QuickDraw space) But these are _MUCH_ more
  1499.                                                          difficult to test for in a quick way }
  1500.         kOurMaxHandleSize        = 256;                    { our Max handle size }
  1501.  
  1502.     VAR
  1503.         fInfo:                FontInfo;
  1504.         savedHText:         Handle;
  1505.         sysJust:            INTEGER;
  1506.         { these next two locals eat up lots of stack space...this could be improved by allocating
  1507.         a pointer for the one that is used (eg allocate a pointer for myCQDProcs if CDQ available) }
  1508.         myQDProcs:            QDProcs;
  1509.         myCQDProcs:         CQDProcs;
  1510.         hadQDProcs:            BOOLEAN;
  1511.         saveRectProc:        ProcPtr;
  1512.  
  1513.     PROCEDURE InitMyPrivateTE;
  1514.  
  1515.         CONST
  1516.             kZoneHeader         = 52;                    { 52 bytes for header }
  1517.             kZoneTrailer        = 12;                    { 12 bytes for trailer }
  1518.             kMPBlockHeader        = 8;                    { 8 bytes for Master Pointer block hdr }
  1519.             kInitialMstrPtrs    = 2;                    { 2 master pointers created initially }
  1520.             kSlop                = 32;                    { bytes of slop (just in case) }
  1521.             kZoneOverhead        = kZoneHeader + kZoneTrailer + kMPBlockHeader +
  1522.                                   4 * kInitialMstrPtrs + kSlop; { how large the zone overhead is }
  1523.  
  1524.         VAR
  1525.             aTEZonePtr:         Ptr;
  1526.             startPtr:            Ptr;
  1527.  
  1528.         BEGIN
  1529.         pMATextBoxHText := NIL;
  1530.  
  1531.         gMATextBoxTE := TENew(box, box);
  1532.         IF (gMATextBoxTE = NIL) THEN                    { can't allocate space for our terecord }
  1533.             exit(InitMyPrivateTE);
  1534.  
  1535.         { • save off several items of interest }
  1536.         WITH gMATextBoxTE^^ DO
  1537.             BEGIN
  1538.             gTEDefaultWordBreak := wordBreak;
  1539.             pSaveHText := hText;                        { save the text handle }
  1540.             END;
  1541.  
  1542.         { • Since TESetText (called near the end of MATextBox) hits the heap, we can speed this hit
  1543.         to the heap for small text lengths (<= 255), by allocating a special text handle in its own
  1544.         separate heap. We'll use this text handle whenever the text length is <= 255. }
  1545.  
  1546.         { • create a separate heap }
  1547.         aTEZonePtr := NewPtr(kOurMaxHandleSize + kZoneOverhead);
  1548.         IF (aTEZonePtr = NIL) THEN                        { can't allocate space for our heap }
  1549.             exit(InitMyPrivateTE);
  1550.         startPtr := Ptr(StripLong(aTEZonePtr));
  1551.         InitZone(NIL, kInitialMstrPtrs, Ptr(Ord(startPtr) + GetPtrSize(aTEZonePtr)), startPtr);
  1552.  
  1553.         { • InitZone sets the current zone to the newly created zone }
  1554.  
  1555.         { • allocate our new text handle in our new heap zone }
  1556.         pMATextBoxHText := NewHandle(kOurMaxHandleSize);     { the text handle }
  1557.  
  1558.         { • restore the heap zone  }
  1559.         SetZone(ApplicZone);
  1560.         END;
  1561.  
  1562.     FUNCTION IsColorPort(aGrafPtr: GrafPtr): BOOLEAN;
  1563.  
  1564.         BEGIN
  1565.         IsColorPort :=  (qNeedsColorQD | gConfiguration.hasColorQD)
  1566.         & (BAND(CGrafPtr(aGrafPtr)^.portVersion, $C000) = $0000C000)  { 2 hi bits. IM V pp. 49-50 }
  1567.         END;
  1568.  
  1569.  
  1570.     BEGIN
  1571.     { Create my goodies if necessary }
  1572.     IF gMATextBoxTE = NIL THEN
  1573.         BEGIN
  1574.         InitMyPrivateTE;
  1575.  
  1576.         IF gMATextBoxTE = NIL THEN                        { couldn't allocate the TE handle }
  1577.             BEGIN
  1578.             TextBox(text, itsLength, box, itsJust);     { default to TextBox in low memory }
  1579.             exit(MATextBox);
  1580.             END;
  1581.         END;
  1582.  
  1583.     { Setup the work TE with the necessary parameters }
  1584.     GetFontInfo(fInfo);                                 { Need to get font's height and ascent. }
  1585.  
  1586.     { Horse the intersection of the clip and the box into the TE's viewRect
  1587.     and then only draw at all if that rect is non empty }
  1588.     IF SectRect(thePort^.clipRgn^^.rgnBBox, box, gMATextBoxTE^^.viewRect) THEN
  1589.         BEGIN
  1590.         WITH gMATextBoxTE^^, fInfo DO
  1591.             BEGIN
  1592.             destRect := box;
  1593.             IF NOT spaceForCaret THEN                        { widen the destrect but not the visrect.
  1594.                                                              This lets the 1 pixel wide area to the
  1595.                                                              left of all text and the right of all text
  1596.                                                              go unshown. }
  1597.                 BEGIN
  1598.                 WITH destRect DO
  1599.                     BEGIN
  1600.                     left := left - kTextBoxCaretSlopSize;
  1601.                     right := right + kTextBoxCaretSlopSize;
  1602.                     END;
  1603.                 END;
  1604.  
  1605.  
  1606.             { Enforce minimum width on destRect ala IM-I pp. 383.  Although the text says that
  1607.             20 is a good number, using the widMax ensures that it is correct for all font sizes. }
  1608.             WITH destRect DO
  1609.                 right := left + Max(Max(right - left, widMax), 20);
  1610.     
  1611.             inPort := thePort;                                { Current port and its characteristics }
  1612.     
  1613.             txSize := thePort^.txSize;
  1614.             txFont := thePort^.txFont;
  1615.             txFace := thePort^.txFace;
  1616.             fontAscent := ascent;
  1617.             lineHeight := ascent + descent + leading;
  1618.  
  1619.             TESetJust(itsJust, gMATextBoxTE);                { be good, use the trap }
  1620.     
  1621.             IF autoWrap THEN
  1622.                 crOnly := 0                                 {if >=0, word wrap}
  1623.             ELSE
  1624.                 crOnly := - 1;                                {if <0, new line at Return only}
  1625.     
  1626.             wordBreak := gTEDefaultWordBreak;
  1627.             END;
  1628.     
  1629.         IF wordBreak <> NIL THEN
  1630.             SetWordBreak(wordBreak, gMATextBoxTE);            { set the word break routine }
  1631.     
  1632.         IF (pMATextBoxHText <> NIL) THEN                    { if our private heap is set up }
  1633.             BEGIN
  1634.             IF itsLength <= kOurMaxHandleSize  THEN        { short strings go in the mini-heap }
  1635.                 gMATextBoxTE^^.hText := pMATextBoxHText
  1636.             ELSE
  1637.                 gMATextBoxTE^^.hText := pSaveHText;
  1638.             END;
  1639.     
  1640.         TESetText(text, Min(itsLength, kMaxTEChars), gMATextBoxTE);
  1641.     
  1642.         { if called with eraseFirst TRUE, then let TEUpdate image with its built-in EraseRect }
  1643.         IF eraseFirst THEN
  1644.             BEGIN
  1645.             EraseRect(gMATextBoxTE^^.viewRect); { Oh yeah?  Some versions of TE _DON'T_ erase first! }
  1646.             TEUpdate(box, gMATextBoxTE);
  1647.             END
  1648.         ELSE
  1649.             BEGIN
  1650.             { replace the existing QD procs ( standard or externally supplied )
  1651.             so that the (<potential>, see comment above) EraseRect in TEUpdate is ignored }
  1652.     
  1653.             IF thePort^.grafProcs <> NIL THEN
  1654.                 BEGIN
  1655.                 hadQDProcs := TRUE;
  1656.                 saveRectProc := thePort^.grafProcs^.rectProc;
  1657.                 thePort^.grafProcs^.rectProc := @StdNoRect;
  1658.                 END
  1659.             ELSE
  1660.                 BEGIN
  1661.                 hadQDProcs := FALSE;
  1662.                 IF IsColorPort(thePort) THEN
  1663.                     BEGIN
  1664.                     SetStdCProcs(myCQDProcs);
  1665.                     myCQDProcs.rectProc := @StdNoRect;
  1666.                     thePort^.grafProcs := @myCQDProcs;
  1667.                     END
  1668.                 ELSE
  1669.                     BEGIN
  1670.                     SetStdProcs(myQDProcs);
  1671.                     myQDProcs.rectProc := @StdNoRect;
  1672.                     thePort^.grafProcs := @myQDProcs;
  1673.                     END;
  1674.                 END;
  1675.     
  1676.             { Now do the imaging }
  1677.             TEUpdate(box, gMATextBoxTE);
  1678.     
  1679.             { Restore the QDProcs or eliminate the QDProcs, take yer pick. }
  1680.             IF hadQDProcs THEN
  1681.                 thePort^.grafProcs^.rectProc := saveRectProc
  1682.             ELSE
  1683.                 thePort^.grafProcs := NIL;
  1684.                 
  1685.             END;
  1686.         END;
  1687.     END;
  1688.  
  1689. {--------------------------------------------------------------------------------------------------}
  1690. {$S MAUtilitiesRes}
  1691.  
  1692. PROCEDURE MADrawString(s: StringPtr;
  1693.                        box: Rect;
  1694.                        justification: INTEGER);
  1695.  
  1696.     VAR
  1697.         theFontInfo:        FontInfo;
  1698.         widthOfString:        INTEGER;
  1699.         boxWidth:            INTEGER;
  1700.  
  1701.     BEGIN
  1702.     GetFontInfo(theFontInfo);
  1703.     widthOfString := StringWidth(s^);
  1704.     WITH box DO
  1705.         BEGIN
  1706.         boxWidth := right - left;
  1707.         IF widthOfString < boxWidth THEN
  1708.             BEGIN
  1709.             CASE GetActualJustification(justification) OF
  1710.                 teJustLeft: ;
  1711.                 teJustCenter:
  1712.                     left := left + (boxWidth - widthOfString) DIV 2;
  1713.                 teJustRight:
  1714.                     left := left + boxWidth - widthOfString;
  1715.                 teForceLeft: ;
  1716.             END;
  1717.             END;
  1718.  
  1719.         MoveTo(left, top + theFontInfo.ascent);
  1720.         DrawString(s^);
  1721.         END;
  1722.     END;
  1723.  
  1724. {--------------------------------------------------------------------------------------------------}
  1725. {$S MAUtilitiesRes}
  1726.  
  1727. FUNCTION PinOnRect(theRect: Rect;
  1728.                    thePt: Point): longint;
  1729.  
  1730.     BEGIN
  1731.     IF thePt.h < theRect.left THEN
  1732.         thePt.h := theRect.left;
  1733.     IF thePt.h > theRect.right THEN
  1734.         thePt.h := theRect.right;
  1735.     IF thePt.v < theRect.top THEN
  1736.         thePt.v := theRect.top;
  1737.     IF thePt.v > theRect.bottom THEN
  1738.         thePt.v := theRect.bottom;
  1739.  
  1740.     PinOnRect := longint(thePt);
  1741.     END;
  1742.  
  1743. {--------------------------------------------------------------------------------------------------}
  1744. {$S WWSeg}
  1745.  
  1746. FUNCTION ReadInteger(prompt: Str255): INTEGER;
  1747.  
  1748.     VAR
  1749.         i:                    INTEGER;
  1750.  
  1751.     BEGIN
  1752.     {$IFC qDebug}
  1753.     DebugForceOutput(forceOn, forceUnchanged);
  1754.     {$EndC}
  1755.     Write(prompt);
  1756.     Readln(i);
  1757.     {$IFC qDebug}
  1758.     DebugEndForce;
  1759.     {$EndC}
  1760.     ReadInteger := i;
  1761.     END;
  1762.  
  1763. {--------------------------------------------------------------------------------------------------}
  1764. {$S WWSeg}
  1765.  
  1766. FUNCTION ReadYesNo(prompt: Str255): Boolean;
  1767.  
  1768.     VAR
  1769.         s:                    Str255;
  1770.  
  1771.     BEGIN
  1772.     {$IFC qDebug}
  1773.     DebugForceOutput(forceOn, forceUnchanged);
  1774.     {$EndC}
  1775.     Write(prompt);
  1776.     Readln(s);
  1777.     {$IFC qDebug}
  1778.     DebugEndForce;
  1779.     {$EndC}
  1780.     ReadYesNo := (s <> '') & (s[1] IN ['y', 'Y']);
  1781.     END;
  1782.  
  1783. {--------------------------------------------------------------------------------------------------}
  1784. {$S MAUtilitiesRes}
  1785.  
  1786. FUNCTION RectsNest(outer, inner: Rect): Boolean;
  1787.  
  1788.     BEGIN
  1789.     WITH inner DO
  1790.         RectsNest := (left >= outer.left) & (right <= outer.right) & (top >= outer.top) & (bottom <=
  1791.                      outer.bottom);
  1792.     END;
  1793.  
  1794. {--------------------------------------------------------------------------------------------------}
  1795. {$S MAUtilitiesRes}
  1796.  
  1797. FUNCTION VRectsNest(outer, inner: VRect): Boolean;
  1798.  
  1799.     BEGIN
  1800.     WITH inner DO
  1801.         VRectsNest := (left >= outer.left) & (right <= outer.right) & (top >= outer.top) &
  1802.                       (bottom <= outer.bottom);
  1803.     END;
  1804.  
  1805. {--------------------------------------------------------------------------------------------------}
  1806. {$S MAUtilitiesRes}
  1807.  
  1808. FUNCTION RoundUp(aNumber: longint;
  1809.                  aModulus: INTEGER): longint;
  1810.  
  1811.     BEGIN
  1812.     RoundUp := ((aNumber + aModulus - 1) DIV aModulus) * aModulus;
  1813.     END;
  1814.  
  1815. {--------------------------------------------------------------------------------------------------}
  1816. {$S MAUtilitiesRes}
  1817.  
  1818. PROCEDURE ScrapStuffFields(aTitle: Str255;
  1819.                            VAR aScrapStuff: ScrapStuff;
  1820.                            PROCEDURE DoToField(fieldName: Str255;
  1821.                                                fieldAddr: Ptr;
  1822.                                                fieldType: INTEGER));
  1823.  
  1824.     BEGIN
  1825.     DoToField(aTitle, NIL, bTitle);
  1826.     DoToField('  scrapSize', @aScrapStuff.scrapSize, bLongint);
  1827.     DoToField('  scrapHandle', @aScrapStuff.scrapHandle, bHandle);
  1828.     DoToField('  scrapCount', @aScrapStuff.scrapCount, bInteger);
  1829.     DoToField('  scrapState', @aScrapStuff.scrapState, bInteger);
  1830.     IF aScrapStuff.scrapName <> NIL THEN
  1831.         DoToField('  scrapName', @aScrapStuff.scrapName^, bString)
  1832.     ELSE
  1833.         DoToField('  scrapName', NIL, bPointer);
  1834.     END;
  1835.  
  1836. {--------------------------------------------------------------------------------------------------}
  1837. {$S MAUtilitiesRes}
  1838.  
  1839. FUNCTION SetKeyScript(newKeyScript: INTEGER): INTEGER;
  1840.  
  1841.     VAR
  1842.         currentKeyScript:    INTEGER;
  1843.  
  1844.     BEGIN
  1845.     IF qNeedsScriptManager | gConfiguration.hasScriptManager THEN
  1846.         BEGIN
  1847.         currentKeyScript := GetEnvirons(smKeyScript);
  1848.         IF currentKeyScript <> newKeyScript THEN
  1849.             KeyScript(newKeyScript);
  1850.         SetKeyScript := currentKeyScript;
  1851.         END
  1852.     ELSE
  1853.         BEGIN
  1854.         { ??? what it the correct thing to do if we get here? }
  1855.         END;
  1856.     END;
  1857.  
  1858. {--------------------------------------------------------------------------------------------------}
  1859. {$S MAUtilitiesRes}                                     {Must be in Main segment and cannot call to
  1860.                                                          any other segment.}
  1861.  
  1862. PROCEDURE SetHandleBits(h: Handle;
  1863.                         theBits: SignedByte);
  1864.  
  1865.     BEGIN
  1866.     IF qNeedsROM128K | gConfiguration.hasROM128K THEN
  1867.         HSetState(h, theBits)
  1868.     ELSE
  1869.         SignedBytePtr(h)^ := theBits;
  1870.     END;
  1871.  
  1872. {--------------------------------------------------------------------------------------------------}
  1873. {$IFC NOT qNeedsColorQD}                                { Becomes an inline if we know the machine
  1874.                                                          has color QD }
  1875. {$S MAUtilitiesRes}
  1876.  
  1877. PROCEDURE SetIfBkColor(aColor: RGBColor);
  1878.  
  1879.     CONST
  1880.         SignBit             = 15;
  1881.  
  1882.     VAR
  1883.         index:                INTEGER;
  1884.         oldColor:            longint;
  1885.  
  1886.     BEGIN
  1887.     IF qNeedsColorQD | gConfiguration.hasColorQD THEN
  1888.         BEGIN
  1889.         { if not color port or color doesn't match then make trap }
  1890.         WITH CGrafPtr(thePort)^ DO
  1891.             IF (BAND(portVersion, $C000) <> $0000C000) | NOT EqualBlocks(@rgbBkColor, @aColor,
  1892.                                                                          sizeof(RGBColor)) THEN
  1893.                 RGBBackColor(aColor);
  1894.         END
  1895.     ELSE
  1896.         BEGIN
  1897.         index := 0;                                     { Prime index }
  1898.         IF BTST(aColor.red, SignBit) THEN                { Set bit if red >= $8000 }
  1899.             index := 4;
  1900.         IF BTST(aColor.green, SignBit) THEN             { Set bit if green >= $8000 }
  1901.             index := index + 2;
  1902.         IF BTST(aColor.blue, SignBit) THEN                { Set bit if blue >= $8000 }
  1903.             index := index + 1;
  1904.         CASE index OF
  1905.             0:
  1906.                 oldColor := blackColor;
  1907.             1:
  1908.                 oldColor := blueColor;
  1909.             2:
  1910.                 oldColor := greenColor;
  1911.             3:
  1912.                 oldColor := cyanColor;
  1913.             4:
  1914.                 oldColor := redColor;
  1915.             5:
  1916.                 oldColor := magentaColor;
  1917.             6:
  1918.                 oldColor := yellowColor;
  1919.             7:
  1920.                 oldColor := whiteColor;
  1921.         END;
  1922.         BackColor(oldColor);
  1923.         END;
  1924.     END;
  1925. {$ENDC}
  1926.  
  1927. {--------------------------------------------------------------------------------------------------}
  1928. {$IFC NOT qNeedsColorQD}                                { Becomes an inline if we know the machine
  1929.                                                          has color QD }
  1930. {$S MAUtilitiesRes}
  1931.  
  1932. PROCEDURE SetIfColor(aColor: RGBColor);
  1933.  
  1934.     CONST
  1935.         SignBit             = 15;
  1936.  
  1937.     VAR
  1938.         index:                INTEGER;
  1939.         oldColor:            longint;
  1940.  
  1941.     BEGIN
  1942.     IF qNeedsColorQD | gConfiguration.hasColorQD THEN
  1943.         BEGIN
  1944.         { if not color port or color doesn't match then make trap }
  1945.         WITH CGrafPtr(thePort)^ DO
  1946.             IF (BAND(portVersion, $C000) <> $0000C000) | NOT EqualBlocks(@rgbFgColor, @aColor,
  1947.                                                                          sizeof(RGBColor)) THEN
  1948.                 RGBForeColor(aColor);
  1949.         END
  1950.     ELSE
  1951.         BEGIN
  1952.         index := 0;                                     { Prime index }
  1953.         IF BTST(aColor.red, SignBit) THEN                { Set bit if red >= $8000 }
  1954.             index := 4;
  1955.         IF BTST(aColor.green, SignBit) THEN             { Set bit if green >= $8000 }
  1956.             index := index + 2;
  1957.         IF BTST(aColor.blue, SignBit) THEN                { Set bit if blue >= $8000 }
  1958.             index := index + 1;
  1959.         CASE index OF
  1960.             0:
  1961.                 oldColor := blackColor;
  1962.             1:
  1963.                 oldColor := blueColor;
  1964.             2:
  1965.                 oldColor := greenColor;
  1966.             3:
  1967.                 oldColor := cyanColor;
  1968.             4:
  1969.                 oldColor := redColor;
  1970.             5:
  1971.                 oldColor := magentaColor;
  1972.             6:
  1973.                 oldColor := yellowColor;
  1974.             7:
  1975.                 oldColor := whiteColor;
  1976.         END;
  1977.         ForeColor(oldColor);
  1978.         END;
  1979.     END;
  1980. {$ENDC}
  1981.  
  1982. {--------------------------------------------------------------------------------------------------}
  1983. {$S MAUtilitiesRes}
  1984.  
  1985. PROCEDURE GetPortTextStyle(theTextStyle: TextStyle);
  1986.  
  1987.     BEGIN
  1988.     WITH thePort^, theTextStyle DO
  1989.         BEGIN
  1990.         tsFont := txFont;
  1991.         tsFace := txFace;
  1992.         tsSize := txSize;
  1993.         GetIfColor(tsColor);
  1994.         END;
  1995.     END;
  1996.  
  1997. {--------------------------------------------------------------------------------------------------}
  1998. {$S MAUtilitiesRes}
  1999.  
  2000. PROCEDURE SetPortTextStyle(theTextStyle: TextStyle);
  2001.  
  2002.     BEGIN
  2003.     { Don't make the traps unless we need to }
  2004.     WITH thePort^, theTextStyle DO
  2005.         BEGIN
  2006.         IF txFont <> tsFont THEN
  2007.             TextFont(tsFont);
  2008.         IF txFace <> tsFace THEN
  2009.             TextFace(tsFace);
  2010.         IF txSize <> tsSize THEN
  2011.             TextSize(tsSize);
  2012.         SetIfColor(tsColor);
  2013.         END;
  2014.     END;
  2015.  
  2016. {--------------------------------------------------------------------------------------------------}
  2017. {$Push}                                                 { Must be in Main segment, and generic code,
  2018.                                                          because InitToolBox calls this }
  2019. {$MC68020-}
  2020. {$S MAUtilitiesRes}
  2021.  
  2022. PROCEDURE SetRGBColor(VAR RGB: RGBColor;
  2023.                       red, green, blue: INTEGER);
  2024.  
  2025.     BEGIN
  2026.     RGB.red := red;
  2027.     RGB.green := green;
  2028.     RGB.blue := blue;
  2029.     END;
  2030. {$Pop}
  2031.  
  2032. {--------------------------------------------------------------------------------------------------}
  2033. {$S MAUtilitiesRes}
  2034.  
  2035. PROCEDURE SetTextStyle(VAR theTextStyle: TextStyle;
  2036.                        theFont: INTEGER;
  2037.                        theStyle: Style;
  2038.                        theSize: INTEGER;
  2039.                        theColor: RGBColor);
  2040.  
  2041.     BEGIN
  2042.     WITH theTextStyle DO
  2043.         BEGIN
  2044.         tsFont := theFont;
  2045.         tsFace := theStyle;
  2046.         tsSize := theSize;
  2047.         tsColor := theColor;
  2048.         END;
  2049.     END;
  2050.  
  2051. {--------------------------------------------------------------------------------------------------}
  2052. {$S MADebug}
  2053.  
  2054. PROCEDURE StdFieldToString(theData: Ptr;
  2055.                            fieldType: INTEGER;
  2056.                            VAR theString: Str255);
  2057.  
  2058.     CONST
  2059.         adnFrame            = [adnLineTop, adnLineLeft, adnLineBottom, adnLineRight];
  2060.         kDecPrec            = 4;                        { Change this if you want more decimal
  2061.                                                          precision in extended}
  2062.  
  2063.     TYPE
  2064.         TAlias                = RECORD
  2065.             CASE INTEGER OF
  2066.                 bBoolean:
  2067.                     (asBoolean:          Boolean);
  2068.                 bFontName, bCmdNumber, bHighByte, bLowByte, bHexInteger, bInteger:
  2069.                     (asInteger:          INTEGER);
  2070.                 bFixed, bHexLongInt, bLongint:
  2071.                     (asLongInt:          longint);
  2072.                 bString:
  2073.                     (asString:             Str255);
  2074.                 bChar:
  2075.                     (asChar:             CHAR);
  2076.                 bGrafPtr, bWindowPtr, bPointer:
  2077.                     (asPointer:          Ptr);
  2078.                 bRgnHandle, bControlHandle, bTEHandle, bHandle:
  2079.                     (asHandle:             Handle);
  2080.                 bPoint:
  2081.                     (asPoint:             Point);
  2082.                 bRect:
  2083.                     (asRect:             Rect);
  2084.                 bObject:
  2085.                     (asObject:             Handle);
  2086.                 bByte:
  2087.                     (asByte:             SignedByte);
  2088.                 bHLState:
  2089.                     (asHLState:          SignedByte);
  2090.                 bIdType, bResType, bOSType:
  2091.                     (asOSType:             OSType);
  2092.                 bPattern:
  2093.                     (asPattern:          Pattern);
  2094.                 bRGBColor:
  2095.                     (asRGBColor:         RGBColor);
  2096.                 bStyle:
  2097.                     (asStyle:             Style);
  2098.                 bVCoordinate:
  2099.                     (asVCoordinate:      VCoordinate);
  2100.                 bVPoint:
  2101.                     (asVPoint:             VPoint);
  2102.                 bVRect:
  2103.                     (asVRect:             VRect);
  2104.                 bStringHandle:
  2105.                     (asStrHandle:         StringHandle);
  2106.                 bCntlAdornment:
  2107.                     (asCntlAdornment:     CntlAdornment);
  2108.                 bSizeDeterminer:
  2109.                     (asSizeDeterminer:     SignedByte);
  2110.                 bReal, bSingle:
  2111.                     (asReal:             Real);
  2112.                 bDouble:
  2113.                     (asDouble:             Double);
  2114.                 bExtended:
  2115.                     (asExtended:         Extended);
  2116.                 bVHSelect:
  2117.                     (asVHSelect:         VHSelect);
  2118.             END;
  2119.  
  2120.     VAR
  2121.         alias:                ^TAlias;
  2122.         aString:            Str255;
  2123.         hexString:            String8;
  2124.         i:                    INTEGER;
  2125.         { Extended support }
  2126.         aDecForm:            DecForm;
  2127.         x:                    Extended;
  2128.         NumStr:             DecStr;
  2129.  
  2130.     PROCEDURE CheckStyleItem(s: StyleItem;
  2131.                              name: Str255);
  2132.  
  2133.         BEGIN
  2134.         IF s IN alias^.asStyle THEN
  2135.             IF theString = '[' THEN
  2136.                 theString := CONCAT(theString, name)
  2137.             ELSE
  2138.                 theString := CONCAT(theString, ',', name);
  2139.         END;
  2140.  
  2141.     PROCEDURE CheckAdornment(p: CntlAdornment;
  2142.                              name: Str255);
  2143.  
  2144.         BEGIN
  2145.         { "set1 <= set2" means set1 is wholly contained in set2 }
  2146.         IF p <= alias^.asCntlAdornment THEN
  2147.             IF theString = '[' THEN
  2148.                 theString := CONCAT(theString, name)
  2149.             ELSE
  2150.                 theString := CONCAT(theString, ',', name);
  2151.         END;
  2152.  
  2153.     BEGIN
  2154.     alias := Pointer(theData);
  2155.     theString := '';
  2156.     WITH alias^ DO
  2157.         CASE fieldType OF
  2158.             bBoolean:
  2159.                 BEGIN
  2160.                 NumberToHex(asByte, theString, 2);
  2161.                 Insert(' (', theString, 1);
  2162.                 theString := CONCAT(theString, ')');
  2163.                 Insert(gBoolString[Ord(asBoolean) <> 0], theString, 1);
  2164.                 END;
  2165.             bFontName:
  2166.                 GetFontName(asInteger, theString);
  2167.             bInteger:
  2168.                 NumToString(asInteger, theString);
  2169.             bLongint:
  2170.                 NumToString(asLongInt, theString);
  2171.             bHexInteger:
  2172.                 NumberToHex(asInteger, theString, 4);
  2173.             bHexLongInt:
  2174.                 NumberToHex(asLongInt, theString, 8);
  2175.             bHighByte:
  2176.                 NumberToHex(BSR(BAND(asInteger, $FF00), 8), theString, 2);
  2177.             bLowByte:
  2178.                 NumberToHex(BAND(asInteger, $00FF), theString, 2);
  2179.             bFixed:
  2180.                 BEGIN
  2181.                 NumToString(HiWrd(asLongInt), aString);
  2182.                 NumToString(LoWrd(asLongInt), theString);
  2183.                 theString := CONCAT(aString, ':', theString);
  2184.                 END;
  2185.             bString:
  2186.                 theString := asString;
  2187.             bChar:
  2188.                 BEGIN
  2189.                 theString := ' ';
  2190.                 theString[1] := asChar;
  2191.                 END;
  2192.             bGrafPtr, bWindowPtr, bPointer:
  2193.                 BEGIN
  2194.                 PointerToHex(ORD4(asPointer), aString, 8);
  2195.                 IF Odd(ORD4(asPointer)) THEN
  2196.                     theString := CONCAT('INVALID! (', aString, ')')
  2197.                 ELSE IF asHandle = NIL THEN
  2198.                     theString := 'Nil'
  2199.                 ELSE
  2200.                     theString := aString;
  2201.                 END;
  2202.             bRgnHandle, bControlHandle, bTEHandle, bHandle:
  2203.                 BEGIN
  2204.                 PointerToHex(ORD4(asHandle), aString, 8);
  2205.                 IF Odd(ORD4(asHandle)) THEN
  2206.                     theString := CONCAT('INVALID! (', aString, ')')
  2207.                 ELSE IF asHandle = NIL THEN
  2208.                     theString := 'Nil'
  2209.                 ELSE
  2210.                     theString := aString;
  2211.                 END;
  2212.             bPoint:
  2213.                 BEGIN
  2214.                 NumToString(asPoint.h, aString);
  2215.                 NumToString(asPoint.v, theString);
  2216.                 theString := CONCAT('(h:', aString, ', v:', theString, ')');
  2217.                 END;
  2218.             bRect:
  2219.                 BEGIN
  2220.                 NumToString(asRect.left, aString);
  2221.                 NumToString(asRect.top, theString);
  2222.                 theString := CONCAT('(l:', aString, ', t:', theString, ')/(r:');
  2223.                 NumToString(asRect.right, aString);
  2224.                 theString := CONCAT(theString, aString, ', b:');
  2225.                 NumToString(asRect.bottom, aString);
  2226.                 theString := CONCAT(theString, aString, ')');
  2227.                 END;
  2228.             bObject:
  2229.                 BEGIN
  2230.                 PointerToHex(ORD4(asObject), aString, 8);
  2231.                 IF Odd(ORD4(asObject)) THEN
  2232.                     theString := CONCAT('INVALID! (', aString, ')')
  2233.                 ELSE IF asObject = NIL THEN
  2234.                     theString := 'Nil'
  2235.                 ELSE
  2236.                     theString := aString;
  2237.                 END;
  2238.             bByte:
  2239.                 NumToString(asByte, theString);
  2240.             bHLState:
  2241.                 CASE asHLState OF
  2242.                     1:
  2243.                         theString := 'hlOff';
  2244.                     2:
  2245.                         theString := 'hlDim';
  2246.                     4:
  2247.                         theString := 'hlOn';
  2248.                     OTHERWISE
  2249.                         BEGIN
  2250.                         NumToString(asHLState, aString);
  2251.                         theString := CONCAT('INVALID! (', aString, ')');
  2252.                         END;
  2253.                 END;
  2254.             bCmdNumber:
  2255.                 NumToString(asInteger, theString);
  2256.             bIdType, bResType, bOSType:
  2257.                 BEGIN
  2258.                 theString := '''    ''';
  2259.                 FOR i := 1 TO 4 DO
  2260.                     theString[i + 1] := asOSType[i];
  2261.                 END;
  2262.             bPattern:
  2263.                 BEGIN
  2264.                 theString := '$';
  2265.                 FOR i := 0 TO 7 DO
  2266.                     BEGIN
  2267.                     LIntToHex(asPattern[i], hexString, 2);
  2268.                     theString := CONCAT(theString, hexString);
  2269.                     END;
  2270.                 END;
  2271.             bRGBColor:
  2272.                 WITH asRGBColor DO
  2273.                     IF (red = 0) & (green = 0) & (blue = 0) THEN
  2274.                         theString := 'Black'
  2275.                     ELSE IF (red = $FFFF) & (green = $FFFF) & (blue = $FFFF) THEN
  2276.                         theString := 'White'
  2277.                     ELSE
  2278.                         BEGIN
  2279.                         NumberToHex(asRGBColor.red, theString, 4);
  2280.                         NumberToHex(asRGBColor.green, aString, 4);
  2281.                         theString := CONCAT(theString, '/', aString);
  2282.                         NumberToHex(asRGBColor.blue, aString, 4);
  2283.                         theString := CONCAT(theString, '/', aString);
  2284.                         END;
  2285.             bStyle:
  2286.                 BEGIN
  2287.                 theString := '[';
  2288.                 CheckStyleItem(bold, 'bold');
  2289.                 CheckStyleItem(italic, 'italic');
  2290.                 CheckStyleItem(underline, 'underline');
  2291.                 CheckStyleItem(outline, 'outline');
  2292.                 CheckStyleItem(shadow, 'shadow');
  2293.                 CheckStyleItem(condense, 'condense');
  2294.                 CheckStyleItem(extend, 'extend');
  2295.                 theString := CONCAT(theString, ']');
  2296.                 END;
  2297.             bVCoordinate:
  2298.                 NumToString(asVCoordinate, theString);
  2299.             bVPoint:
  2300.                 BEGIN
  2301.                 NumToString(asVPoint.h, aString);
  2302.                 NumToString(asVPoint.v, theString);
  2303.                 theString := CONCAT('(h:', aString, ', v:', theString, ')');
  2304.                 END;
  2305.             bVRect:
  2306.                 BEGIN
  2307.                 NumToString(asVRect.left, aString);
  2308.                 NumToString(asVRect.top, theString);
  2309.                 theString := CONCAT('(l:', aString, ', t:', theString, ')/(r:');
  2310.                 NumToString(asVRect.right, aString);
  2311.                 theString := CONCAT(theString, aString, ', b:');
  2312.                 NumToString(asVRect.bottom, aString);
  2313.                 theString := CONCAT(theString, aString, ')');
  2314.                 END;
  2315.             bStringHandle:
  2316.                 IF asStrHandle = NIL THEN
  2317.                     theString := 'Nil'
  2318.                 ELSE
  2319.                     theString := asStrHandle^^;
  2320.             bCntlAdornment:
  2321.                 BEGIN
  2322.                 theString := '[';
  2323.                 IF adnFrame <= asCntlAdornment THEN
  2324.                     CheckAdornment(adnFrame, 'frame')
  2325.                 ELSE
  2326.                     BEGIN
  2327.                     CheckAdornment([adnLineTop], 'top');
  2328.                     CheckAdornment([adnLineLeft], 'left');
  2329.                     CheckAdornment([adnLineBottom], 'bottom');
  2330.                     CheckAdornment([adnLineRight], 'right');
  2331.                     END;
  2332.                 { CheckAdornment(adnPatFill, 'fill'); }
  2333.                 CheckAdornment([adnOval], 'oval');
  2334.                 CheckAdornment([adnRRect], 'rrect');
  2335.                 CheckAdornment([adnShadow], 'shadow');
  2336.                 theString := CONCAT(theString, ']');
  2337.                 END;
  2338.             bSizeDeterminer:
  2339.                 CASE asSizeDeterminer OF
  2340.                     0:
  2341.                         theString := 'sizeSuperView';
  2342.                     1:
  2343.                         theString := 'sizeRelSuperView';
  2344.                     2:
  2345.                         theString := 'sizePage';
  2346.                     3:
  2347.                         theString := 'sizeFillPages';
  2348.                     4:
  2349.                         theString := 'sizeVariable';
  2350.                     5:
  2351.                         theString := 'sizeFixed';
  2352.                 END;
  2353.             bReal, bSingle:
  2354.                 BEGIN
  2355.                 aDecForm.Style := FixedDecimal;
  2356.                 aDecForm.digits := kDecPrec;
  2357.                 x := asReal;
  2358.                 Num2Str(aDecForm, x, NumStr);
  2359.                 theString := Str255(NumStr);
  2360.                 END;
  2361.             bDouble:
  2362.                 BEGIN
  2363.                 aDecForm.Style := FixedDecimal;
  2364.                 aDecForm.digits := kDecPrec;
  2365.                 x := asDouble;
  2366.                 Num2Str(aDecForm, x, NumStr);
  2367.                 theString := Str255(NumStr);
  2368.                 END;
  2369.             bExtended:
  2370.                 BEGIN
  2371.                 aDecForm.Style := FixedDecimal;
  2372.                 aDecForm.digits := kDecPrec;
  2373.                 x := asExtended;
  2374.                 Num2Str(aDecForm, x, NumStr);
  2375.                 theString := Str255(NumStr);
  2376.                 END;
  2377.             bVHSelect:
  2378.                 BEGIN
  2379.                 CASE asVHSelect OF
  2380.                     v:
  2381.                         theString := 'v';
  2382.                     h:
  2383.                         theString := 'h';
  2384.                     OTHERWISE
  2385.                         BEGIN
  2386.                         NumToString(ORD(asVHSelect), aString);
  2387.                         theString := CONCAT('INVALID! (', aString, ')');
  2388.                         END;
  2389.                 END;
  2390.                 END;
  2391.         END;
  2392.     END;
  2393.  
  2394. {--------------------------------------------------------------------------------------------------}
  2395.  
  2396. FUNCTION StripLong(address: UNIV Ptr): longint;
  2397.     EXTERNAL;
  2398.  
  2399. {--------------------------------------------------------------------------------------------------}
  2400. {$S MAFields}
  2401.  
  2402. PROCEDURE TextStyleFields(aTitle: Str255;
  2403.                           VAR aStyle: TextStyle;
  2404.                           PROCEDURE DoToField(fieldName: Str255;
  2405.                                               fieldAddr: Ptr;
  2406.                                               fieldType: INTEGER));
  2407.  
  2408.     BEGIN
  2409.     DoToField(aTitle, NIL, bTitle);
  2410.     DoToField('  Font', @aStyle.tsFont, bFontName);
  2411.     DoToField('  Face', @aStyle.tsFace, bStyle);
  2412.     DoToField('  Size', @aStyle.tsSize, bInteger);
  2413.     DoToField('  Color', @aStyle.tsColor, bRGBColor);
  2414.     END;
  2415.  
  2416. {--------------------------------------------------------------------------------------------------}
  2417. {$Push}
  2418. {$MC68020-}
  2419. {$S MAUtilitiesRes}
  2420.  
  2421. FUNCTION NumToolboxTraps: INTEGER;
  2422. { InitGraf is always implemented (trap $A86E). If the trap table is big enough, trap $AA6E
  2423. will always point to either Unimplemented or some other trap, but will never be the same
  2424. as InitGraf. Thus, you can check the size of the trap table by asking if the address of
  2425. trap $A86E is the same as $AA6E. }
  2426.  
  2427.     BEGIN
  2428.     IF NGetTrapAddress(_InitGraf, ToolTrap) = NGetTrapAddress($AA6E, ToolTrap) THEN
  2429.         NumToolboxTraps := $200
  2430.     ELSE
  2431.         NumToolboxTraps := $400;
  2432.     END;
  2433. {$Pop}
  2434.  
  2435. {--------------------------------------------------------------------------------------------------}
  2436. {$Push}
  2437. {$MC68020-}
  2438. {$S MAUtilitiesRes}
  2439.  
  2440. FUNCTION TrapExists(theTrap: INTEGER): Boolean;
  2441.  
  2442.     VAR
  2443.         theTrapType:        TrapType;
  2444.  
  2445.     BEGIN
  2446.     theTrapType := GetTrapType(theTrap);
  2447.     IF (theTrapType = ToolTrap) THEN
  2448.         BEGIN
  2449.         theTrap := BAND(theTrap, $07FF);
  2450.         IF theTrap >= NumToolboxTraps THEN
  2451.             theTrap := _Unimplemented;
  2452.         END;
  2453.  
  2454.     TrapExists := NGetTrapAddress(_Unimplemented, ToolTrap) <> NGetTrapAddress(theTrap,
  2455.                   theTrapType);
  2456.     END;
  2457. {$Pop}
  2458.  
  2459. {--------------------------------------------------------------------------------------------------}
  2460. {$S MAUtilitiesRes}
  2461.  
  2462. FUNCTION UprChar(ch: CHAR): CHAR;
  2463.  
  2464.     BEGIN
  2465.     IF (ch IN ['a'..'z']) THEN
  2466.         UprChar := CHR(Ord(ch) - 32)
  2467.     ELSE
  2468.         UprChar := ch;
  2469.     END;
  2470.  
  2471. {--------------------------------------------------------------------------------------------------}
  2472. {$S MAUtilitiesRes}
  2473.  
  2474. PROCEDURE UprStr255(VAR s: Str255);
  2475.  
  2476.     VAR
  2477.         i:                    INTEGER;
  2478.  
  2479.     BEGIN
  2480.     FOR i := 1 TO LENGTH(s) DO
  2481.         IF (s[i] IN ['a'..'z']) THEN
  2482.             s[i] := CHR(Ord(s[i]) - 32)
  2483.     END;
  2484.  
  2485. {--------------------------------------------------------------------------------------------------}
  2486. {$S MAUtilitiesRes}
  2487.  
  2488. PROCEDURE UprMAName(VAR s: MAName);
  2489.  
  2490.     VAR
  2491.         i:                    INTEGER;
  2492.  
  2493.     BEGIN
  2494.     FOR i := 1 TO LENGTH(s) DO
  2495.         IF (s[i] IN ['a'..'z']) THEN
  2496.             s[i] := CHR(Ord(s[i]) - 32)
  2497.     END;
  2498.  
  2499. {--------------------------------------------------------------------------------------------------}
  2500. {$S MAUtilitiesRes}
  2501.  
  2502. PROCEDURE UseROMMap(resLoad: Boolean);
  2503.  
  2504.     BEGIN
  2505.     IF qNeedsROM128K | gConfiguration.hasROM128K THEN
  2506.         BEGIN
  2507.         IF resLoad THEN
  2508.             GetROMMapInsert^ := kLMmapTrue
  2509.         ELSE
  2510.             GetROMMapInsert^ := kLMmapFalse;
  2511.         END
  2512.     ELSE
  2513.         SetResLoad(resLoad);
  2514.     END;
  2515.  
  2516. {--------------------------------------------------------------------------------------------------}
  2517. {$S MADebug}
  2518.  
  2519. FUNCTION VerboseIsHandle(h: UNIV Handle): Boolean;
  2520.  
  2521.     CONST
  2522.         kUnInitStorage1     = $72677267;                { Pascal provided uninited storage }
  2523.         kUnInitStorage2     = $67726772;                { odd byte boundary of above }
  2524.         kDebugHandleInit    = $F3F3F3F3;                { Handles are inited to this in MacApp® }
  2525.         kDebugPtrInit        = $F5F5F5F5;                { Pointers are inited to this in MacApp® }
  2526.         kDebugObjInit        = $F1F1F1F1;                { Objects are inited to this in MacApp® }
  2527.  
  2528.     VAR
  2529.         masterPointer:        Ptr;
  2530.  
  2531.     BEGIN
  2532.     VerboseIsHandle := FALSE;
  2533.  
  2534.     IF Odd(Ord(h)) THEN
  2535.         BEGIN
  2536.         IF Ord(h) = kUnInitStorage1 THEN
  2537.             WriteLn('  That handle appears to be from uninitialized storage.')
  2538.         ELSE IF (Ord(h) = kDebugHandleInit) THEN
  2539.             WriteLn('  That handle appears to be from a handle initialized by debugging.')
  2540.         ELSE IF (Ord(h) = kDebugPtrInit) THEN
  2541.             WriteLn('  That handle appears to be from a pointer initialized by debugging.')
  2542.         ELSE IF (Ord(h) = kDebugObjInit) THEN
  2543.             WriteLn('  That handle appears to be an uninitialized instance variable.')
  2544.         ELSE
  2545.             WriteLn('  That handle is odd.');
  2546.         END
  2547.     ELSE IF Ord(h) = kUnInitStorage2 THEN
  2548.         WriteLn('  That handle appears to be from uninitialized storage.')
  2549.     ELSE IF h = NIL THEN
  2550.         WriteLn('  That handle is NIL.')
  2551.     ELSE
  2552.         BEGIN
  2553.         masterPointer := Ptr(StripLong(h^));
  2554.         IF Odd(Ord(masterPointer)) THEN
  2555.             WriteLn('  The master pointer is odd.')
  2556.         ELSE IF IsFreeHandle(h) THEN
  2557.             WriteLn('  The handle has been freed.')
  2558.         ELSE IF ((masterPointer <> NIL) & NOT TestRecoverHandle(masterPointer, h)) THEN
  2559.             WriteLn('  The alleged heap header is invalid.')
  2560.         ELSE
  2561.             VerboseIsHandle := TRUE;
  2562.         END;
  2563.     END;
  2564.  
  2565. {--------------------------------------------------------------------------------------------------}
  2566. {$S MAUtilitiesRes}
  2567.  
  2568. PROCEDURE WithApplicationResFileDo(PROCEDURE DoWithResFile);
  2569. {??? Needs a failure handler ???}
  2570.  
  2571.     VAR
  2572.         oldResFile:         INTEGER;
  2573.  
  2574.     BEGIN
  2575.     oldResFile := CurResFile;
  2576.     UseResFile(gApplicationRefNum);
  2577.     DoWithResFile;
  2578.     UseResFile(oldResFile);
  2579.     END;
  2580.  
  2581. {--------------------------------------------------------------------------------------------------}
  2582. {$S WWSeg}
  2583.  
  2584. PROCEDURE WriteHandleContents(theHandle: UNIV Handle);
  2585.  
  2586.     VAR
  2587.         Max, index:         Size;
  2588.         wasLocked:            Boolean;
  2589.  
  2590.     BEGIN
  2591.     Max := GetHandleSize(theHandle) - 1;
  2592.     IF Max > 0 THEN
  2593.         BEGIN
  2594.         wasLocked := IsHandleLocked(theHandle);
  2595.         IF NOT wasLocked THEN
  2596.             HLock(theHandle);
  2597.         FOR index := 0 TO Max DO
  2598.             Write(CHR(Ptr(Ord(theHandle^) + index)^));
  2599.         IF NOT wasLocked THEN
  2600.             HUnLock(theHandle);
  2601.         END
  2602.     ELSE
  2603.         Write('**Empty**');
  2604.     END;
  2605.  
  2606. {--------------------------------------------------------------------------------------------------}
  2607. {$S WWSeg}
  2608.  
  2609. PROCEDURE WrLblHandleContents(aLabel: Str255;
  2610.                               theHandle: UNIV Handle);
  2611.  
  2612.     BEGIN
  2613.     Write(aLabel, ' = '); WriteHandleContents(theHandle);
  2614.     END;
  2615.  
  2616. {--------------------------------------------------------------------------------------------------}
  2617. {$S WWSeg}
  2618.  
  2619. PROCEDURE WritePt(pt: Point);
  2620.  
  2621.     VAR
  2622.         theString:            Str255;
  2623.  
  2624.     BEGIN
  2625.     FieldToString(@pt, bPoint, theString);
  2626.     Write(theString);
  2627.     END;
  2628.  
  2629. {--------------------------------------------------------------------------------------------------}
  2630. {$S WWSeg}
  2631.  
  2632. PROCEDURE WrLblPt(aLabel: Str255;
  2633.                   pt: Point);
  2634.  
  2635.     BEGIN
  2636.     Write(aLabel, ' = '); WritePt(pt);
  2637.     END;
  2638.  
  2639. {--------------------------------------------------------------------------------------------------}
  2640. {$S WWSeg}
  2641.  
  2642. PROCEDURE WritePtr(val: UNIV longint);
  2643.  
  2644.     VAR
  2645.         theString:            Str255;
  2646.  
  2647.     BEGIN
  2648.     FieldToString(@val, bPointer, theString);
  2649.     Write(theString);
  2650.     END;
  2651.  
  2652. {--------------------------------------------------------------------------------------------------}
  2653. {$S WWSeg}
  2654.  
  2655. PROCEDURE WrLblPtr(aLabel: Str255;
  2656.                    val: UNIV longint);
  2657.  
  2658.     BEGIN
  2659.     Write(aLabel, ' = '); WritePtr(val);
  2660.     END;
  2661.  
  2662. {--------------------------------------------------------------------------------------------------}
  2663. {$S WWSeg}
  2664.  
  2665. PROCEDURE WriteRect(r: Rect);
  2666.  
  2667.     VAR
  2668.         theString:            Str255;
  2669.  
  2670.     BEGIN
  2671.     FieldToString(@r, bRect, theString);
  2672.     Write(theString);
  2673.     END;
  2674.  
  2675. {--------------------------------------------------------------------------------------------------}
  2676. {$S WWSeg}
  2677.  
  2678. PROCEDURE WrLblRect(aLabel: Str255;
  2679.                     r: Rect);
  2680.  
  2681.     BEGIN
  2682.     Write(aLabel, ' = '); WriteRect(r);
  2683.     END;
  2684.  
  2685. {--------------------------------------------------------------------------------------------------}
  2686. {$S WWSeg}
  2687.  
  2688. PROCEDURE WriteBoolean(b: Boolean);
  2689.  
  2690.     VAR
  2691.         theString:            Str255;
  2692.  
  2693.     BEGIN
  2694.     FieldToString(@b, bBoolean, theString);
  2695.     Write(theString);
  2696.     END;
  2697.  
  2698. {--------------------------------------------------------------------------------------------------}
  2699. {$S WWSeg}
  2700.  
  2701. PROCEDURE WrLblBoolean(aLabel: Str255;
  2702.                        b: Boolean);
  2703.  
  2704.     BEGIN
  2705.     Write(aLabel, ' = ');
  2706.     WriteBoolean(b);
  2707.     END;
  2708.  
  2709. {--------------------------------------------------------------------------------------------------}
  2710. {$S WWSeg}
  2711.  
  2712. PROCEDURE WriteVPt(pt: VPoint);
  2713.  
  2714.     VAR
  2715.         theString:            Str255;
  2716.  
  2717.     BEGIN
  2718.     FieldToString(@pt, bVPoint, theString);
  2719.     Write(theString);
  2720.     END;
  2721.  
  2722. {--------------------------------------------------------------------------------------------------}
  2723. {$S WWSeg}
  2724.  
  2725. PROCEDURE WrLblVPt(aLabel: Str255;
  2726.                    pt: VPoint);
  2727.  
  2728.     BEGIN
  2729.     Write(aLabel, ' = '); WriteVPt(pt);
  2730.     END;
  2731.  
  2732. {--------------------------------------------------------------------------------------------------}
  2733. {$S WWSeg}
  2734.  
  2735. PROCEDURE WriteVRect(r: VRect);
  2736.  
  2737.     VAR
  2738.         theString:            Str255;
  2739.  
  2740.     BEGIN
  2741.     FieldToString(@r, bVRect, theString);
  2742.     Write(theString);
  2743.     END;
  2744.  
  2745. {--------------------------------------------------------------------------------------------------}
  2746. {$S WWSeg}
  2747.  
  2748. PROCEDURE WrLblVRect(aLabel: Str255;
  2749.                      r: VRect);
  2750.  
  2751.     BEGIN
  2752.     Write(aLabel, ' = '); WriteVRect(r);
  2753.     END;
  2754.  
  2755. {--------------------------------------------------------------------------------------------------}
  2756. {$S WWSeg}
  2757.  
  2758. PROCEDURE WriteSig(theID: IDType);
  2759.  
  2760.     VAR
  2761.         theString:            Str255;
  2762.  
  2763.     BEGIN
  2764.     FieldToString(@theID, bIdType, theString);
  2765.     Write(theString);
  2766.     END;
  2767.  
  2768. {--------------------------------------------------------------------------------------------------}
  2769. {$S WWSeg}
  2770.  
  2771. PROCEDURE WrLblSig(theLabel: Str255;
  2772.                    theID: IDType);
  2773.  
  2774.     BEGIN
  2775.     Write(theLabel, ' = '); WriteSig(theID);
  2776.     END;
  2777.  
  2778. {--------------------------------------------------------------------------------------------------}
  2779. {$S WWSeg}
  2780.  
  2781. PROCEDURE WriteHexInt(theInt: INTEGER);
  2782.  
  2783.     VAR
  2784.         theString:            Str255;
  2785.  
  2786.     BEGIN
  2787.     FieldToString(@theInt, bHexInteger, theString);
  2788.     Write(theString);
  2789.     END;
  2790.  
  2791. {--------------------------------------------------------------------------------------------------}
  2792. {$S WWSeg}
  2793.  
  2794. PROCEDURE WrLblHexInt(theLabel: Str255;
  2795.                       theInt: INTEGER);
  2796.  
  2797.     BEGIN
  2798.     Write(theLabel, ' = '); WriteHexInt(theInt);
  2799.     END;
  2800.  
  2801. {--------------------------------------------------------------------------------------------------}
  2802. {$S WWSeg}
  2803.  
  2804. PROCEDURE WriteHexLongint(theLongint: longint);
  2805.  
  2806.     VAR
  2807.         theString:            Str255;
  2808.  
  2809.     BEGIN
  2810.     FieldToString(@theLongint, bHexLongInt, theString);
  2811.     Write(theString);
  2812.     END;
  2813.  
  2814. {--------------------------------------------------------------------------------------------------}
  2815. {$S WWSeg}
  2816.  
  2817. PROCEDURE WrLblHexLongint(theLabel: Str255;
  2818.                           theLongint: longint);
  2819.  
  2820.     BEGIN
  2821.     Write(theLabel, ' = '); WriteHexLongint(theLongint);
  2822.     END;
  2823.